CFD Online Logo CFD Online URL
www.cfd-online.com
[Sponsors]
Home > Forums > Software User Forums > ANSYS > CFX

User Fortran with CFX 14.5.7 on winnt_amd64

Register Blogs Community New Posts Updated Threads Search

Like Tree1Likes

Reply
 
LinkBack Thread Tools Search this Thread Display Modes
Old   December 11, 2013, 05:56
Default User Fortran with CFX 14.5.7 on winnt_amd64
  #1
HLo
New Member
 
HLo
Join Date: Dec 2013
Location: Germany
Posts: 26
Rep Power: 12
HLo is on a distinguished road
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
Attached Files
File Type: zip CFX-fortran.zip (2.9 KB, 247 views)
mmhmr69 likes this.
HLo is offline   Reply With Quote

Old   December 19, 2013, 10:31
Talking
  #2
New Member
 
Nolan Dyck
Join Date: Dec 2013
Posts: 13
Rep Power: 12
njdyck is on a distinguished road
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.
njdyck is offline   Reply With Quote

Old   December 19, 2013, 10:46
Default Symbol Table
  #3
HLo
New Member
 
HLo
Join Date: Dec 2013
Location: Germany
Posts: 26
Rep Power: 12
HLo is on a distinguished road
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
HLo is offline   Reply With Quote

Old   December 19, 2013, 11:24
Default
  #4
New Member
 
Nolan Dyck
Join Date: Dec 2013
Posts: 13
Rep Power: 12
njdyck is on a distinguished road
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
njdyck is offline   Reply With Quote

Old   December 20, 2013, 02:55
Default defsym
  #5
HLo
New Member
 
HLo
Join Date: Dec 2013
Location: Germany
Posts: 26
Rep Power: 12
HLo is on a distinguished road
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
HLo is offline   Reply With Quote

Old   December 20, 2013, 04:35
Default
  #6
Member
 
JESS
Join Date: Nov 2010
Posts: 31
Rep Power: 15
Raijin Thunderkeg is on a distinguished road
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.
Raijin Thunderkeg is offline   Reply With Quote

Old   December 20, 2013, 05:18
Default ifort not found
  #7
HLo
New Member
 
HLo
Join Date: Dec 2013
Location: Germany
Posts: 26
Rep Power: 12
HLo is on a distinguished road
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
HLo is offline   Reply With Quote

Old   December 20, 2013, 15:25
Default
  #8
New Member
 
Nolan Dyck
Join Date: Dec 2013
Posts: 13
Rep Power: 12
njdyck is on a distinguished road
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.
njdyck is offline   Reply With Quote

Old   December 21, 2013, 11:13
Default hidden string args
  #9
HLo
New Member
 
HLo
Join Date: Dec 2013
Location: Germany
Posts: 26
Rep Power: 12
HLo is on a distinguished road
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 is offline   Reply With Quote

Old   December 30, 2013, 15:10
Default Solved
  #10
HLo
New Member
 
HLo
Join Date: Dec 2013
Location: Germany
Posts: 26
Rep Power: 12
HLo is on a distinguished road
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
HLo is offline   Reply With Quote

Old   January 1, 2014, 11:52
Default
  #11
New Member
 
Nolan Dyck
Join Date: Dec 2013
Posts: 13
Rep Power: 12
njdyck is on a distinguished road
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 is offline   Reply With Quote

Old   January 6, 2014, 11:40
Smile
  #12
New Member
 
Nolan Dyck
Join Date: Dec 2013
Posts: 13
Rep Power: 12
njdyck is on a distinguished road
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.
njdyck is offline   Reply With Quote

Old   January 6, 2014, 12:43
Default successful test
  #13
HLo
New Member
 
HLo
Join Date: Dec 2013
Location: Germany
Posts: 26
Rep Power: 12
HLo is on a distinguished road
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
HLo is offline   Reply With Quote

Old   January 6, 2014, 13:31
Default
  #14
New Member
 
Nolan Dyck
Join Date: Dec 2013
Posts: 13
Rep Power: 12
njdyck is on a distinguished road
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?

Last edited by njdyck; January 6, 2014 at 15:19.
njdyck is offline   Reply With Quote

Old   January 7, 2014, 09:56
Default #define macros
  #15
HLo
New Member
 
HLo
Join Date: Dec 2013
Location: Germany
Posts: 26
Rep Power: 12
HLo is on a distinguished road
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 is offline   Reply With Quote

Old   January 10, 2014, 14:02
Default Current status
  #16
HLo
New Member
 
HLo
Join Date: Dec 2013
Location: Germany
Posts: 26
Rep Power: 12
HLo is on a distinguished road
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
HLo is offline   Reply With Quote

Old   January 10, 2014, 17:23
Default
  #17
New Member
 
Nolan Dyck
Join Date: Dec 2013
Posts: 13
Rep Power: 12
njdyck is on a distinguished road
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.
njdyck is offline   Reply With Quote

Old   January 16, 2014, 13:48
Default
  #18
ves
Member
 
Veskov Eugene
Join Date: Feb 2011
Posts: 31
Rep Power: 15
ves is on a distinguished road
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?
ves is offline   Reply With Quote

Old   January 16, 2014, 15:33
Default
  #19
New Member
 
Nolan Dyck
Join Date: Dec 2013
Posts: 13
Rep Power: 12
njdyck is on a distinguished road
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.
njdyck is offline   Reply With Quote

Old   January 17, 2014, 12:28
Default
  #20
ves
Member
 
Veskov Eugene
Join Date: Feb 2011
Posts: 31
Rep Power: 15
ves is on a distinguished road
yes, I have windows command promt. CFX command promt compiler not found
ves is offline   Reply With Quote

Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are On


Similar Threads
Thread Thread Starter Forum Replies Last Post
How to set environmental variables of Intel Fortran +CFX? Christine MO CFX 0 September 23, 2011 11:11
Context of user fortran functions Bloshchitsyn Vladimir CFX 0 October 17, 2007 06:28
CFX arc-modeling, User Fortran, CEL.... Bloshchitsyn Vladimir CFX 0 October 15, 2007 06:17
how to use USER FORTRAN with CFX cfd_99 Main CFD Forum 1 June 4, 1999 05:42
CFX User Subroutine Archive David Creech Main CFD Forum 0 March 17, 1999 12:41


All times are GMT -4. The time now is 19:57.