Calling precice directly from preciceFortran.ccp bindings in Fortran 77

Hello,

I am currently working on building a FSI coupling for abaqus using their USUB functions. I have gotten precice to link and am working on getting it running. I ran into a usability issue with the Fortran bindings below is a code snippet from the fortran precice header bindings. I have built preCICE with fortran binding packaged with it. Due to Abaqus USUBS requiring f77 format I have to call the precice fortran c bindings directly from the fortran file and cannot use the precice.f90 module file. The problem is f77 passes everything purely by reference and the binding below request information to be passed by value which f77 cannot do. This requires the precice.f90 module, preciceFortran.hpp and preciceFortran.cpp bindings to be updated to pass by reference only.

/** @file
 * This file contains a Fortran 77 compatible interface written in C/C++.
 * The Fortran bindings are thin wrappers around the C++ API.
 *
 * Every method has a Fortran syntax equivalent in the method comment, and a
 * listing for input and output variables. A variable can be input and output
 * at the same time.
 */

#ifdef __cplusplus
extern "C" {
#endif

///@name Construction and Configuration
///@{

/**
 * Fortran syntax:
 * precicef_create(
 *   CHARACTER participantName(*),
 *   CHARACTER configFileName(*),
 *   INTEGER   solverProcessIndex,
 *   INTEGER   solverProcessSize )
 *
 * IN:  participantName, configFileName, solverProcessIndex, solverProcessSize
 * OUT: -
 *
 * @copydoc precice::Participant::Participant()
 *
 */
PRECICE_API void precicef_create_(
    const char *participantName,
    const char *configFileName,
    const int  *solverProcessIndex,
    const int  *solverProcessSize,
    int         participantNameLength,
    int         configFileNameLength);

///@}

Thank you,

-Justin

I’ll admit upfront that I know nothing about Abaqus. But I would expect there is some way to do what you want because it’s ludicrous for a commercial code to require F77 in 2025.

  1. There is a difference between F77 format (which is properly called fixed-format, as opposed to the modern free-format that doesn’t care about the first 6 columns, etc.) and F77 the language. You can use F90 features and write your source code in fixed-format. Depending on your compiler, it may be seeing a .f extension on a source file and interpreting that as F77 language in fixed format. You may be able to give your file a .f90 extension, or pass appropriate flags to your compiler.
  2. Do you know which Fortran compiler Abaqus is using?
  3. If you’re getting an error message from the compiler, can you post it?

Thank you for the reply. Short answer is you are correct abaqus does not require the file to be compiled in F77. I was incorrect in my interpretation of their documentation. Abaqus is largely still written in fortran 77 syntax and requires a compiler that can handle compiling legacy version since the USUB templates are generally in fixed format and pass purely by reference. This however does not limit the building to only F77 codes. I had to supply the compiler so I could use as new of a compiler as I wanted. Since it does support new compilers I was able to use the preCICE module I just have to compile it separately and link it properly. I have attached what that looks like below for anyone interested in the future including the abaqus usub header.

ifort -V -c -fpp -fPIC -extend_source -DABQ_LNX86_64 -DABQ_FORTRAN -auto -pc64 -align array64byte -prec-div -prec-sqrt -fp-model precise -fimf-arch-consistency=true -mP2OPT_hpo_vec_divbyzero=F -no-fma -fp-speculation=safe -fprotect-parens -fstack-protector-strong -reentrancy threaded -msse3 -axcore-avx2,avx -WB precice.f90  -o ../precice.o

abaqus make library=usub_subroutine_file directory=USUB_LIBS

abaqus job=FSI_TEST double=both usub_lib_dir=$(pwd)/USUB_LIBS scratch=$(pwd)
#abaqus_v6.env 
#-*- mode: python -*-

####################################################################################
#                                                                                  #
#     Compile and Link commands for ABAQUS on the Linux 64-bit Platform            #
#                                                                                  #
####################################################################################

import os, re, glob, driverUtils
abaHomeInc = os.path.abspath(os.path.join(os.environ.get('ABA_HOME', ''), os.pardir))

fortCmd = "ifort"   # <-- Fortran compiler

compile_fortran = [fortCmd,
                   '-V',
                   '-c', '-fpp','-fPIC','-extend_source',
                   '-DABQ_LNX86_64', '-DABQ_FORTRAN',
                   '-auto',    # <-- important for thread-safety of parallel user subroutines
                   '-pc64',                  # set FPU precision to 53 bit significand
                   '-align', 'array64byte',
                   '-prec-div', '-prec-sqrt',# improve precision of FP divides and sqrt
                   '-fp-model', 'precise',   # floating point model: precise
                   '-fimf-arch-consistency=true', # math library consistent results
                   '-mP2OPT_hpo_vec_divbyzero=F',
                   '-no-fma',                # disable floating point fused multiply-add
                   '-fp-speculation=safe',   # floating point speculations only when safe
                   '-fprotect-parens',       # honor parenthesis during expression evaluation
                   '-fstack-protector-strong', # enable stack overflow protection checks
                   '-reentrancy', 'threaded',  # important for thread-safety
                   #'-init=zero','-init=arrays',  # automatically initialize all arrays to zero
                   #'-init=snan', '-init=arrays', # automatically initialize all arrays to SNAN
                   '-msse3',                      # generate SSE3, SSE2, and SSE instructions
                   '-axcore-avx2,avx',    
                   '-WB', '-I%I', '-I'+abaHomeInc, '%P']
link_sl = [fortCmd,
           '-V',           
           '-cxxlib', '-fPIC', '-threads', '-shared','-Wl,--add-needed', 
           '%E', '-Wl,-soname,%U', '-o', '%U', '%F', '%A', "/path/to/precice/mod/object/precice.o",
           "-L/path/to/precice/library/", "-lprecice",
           "-lstdc++", '%L', '%B', '-parallel',           
           '-Wl,-Bdynamic', '-shared-intel']

print(link_sl)
# Remove the temporary names from the namespace
del fortCmd
del abaHomeInc
      subroutine vexternaldb(lOp, i_Array, niArray, r_Array, nrArray)
C
      use precice
      include 'vaba_param.inc'
      
c     
C     Contents of i_Array
      parameter(  i_int_nTotalNodes           = 1,
     *            i_int_nTotalElements        = 2,
     *            i_int_kStep                 = 3,
     *            i_int_kInc                  = 4,
     *            i_int_iStatus               = 5,
     *            i_int_lWriteRestart         = 6,
     *            i_int_ExtraOutputFrame      = 7 )
C     Possible values for the lOp argument
      parameter(  j_int_StartAnalysis         = 0,
     *            j_int_StartStep             = 1,
     *            j_int_SetupIncrement        = 2,
     *            j_int_StartIncrement        = 3,
     *            j_int_EndIncrement          = 4,
     *            j_int_EndStep               = 5,
     *            j_int_EndAnalysis           = 6 )
C     Possible values for i_Array(i_int_iStatus)
      parameter(  j_int_Continue              = 0,
     *            j_int_TerminateStep         = 1,
     *            j_int_TerminateAnalysis     = 2 )
C     Contents of r_Array
      parameter(  i_flt_TotalTime             = 1,
     *            i_flt_StepTime              = 2,
     *            i_flt_dTime                 = 3 )
C     
      dimension   i_Array(niArray), 
     *            r_Array(nrArray)
1 Like

I would also like to add that I believe the comment in this post about the bindings shipping with preCICE being F77 compliant is incorrect. If I call any of the precicef functions while not using the module interface where a name length or other value is expected to be passed by value this can cause problems. Without the module fortran is going to pass the memory reference for the value which is not compatible as a filename of length 17 might be seen as length 67893245 due to the value “17” being passed as the memory address no the length value.

The (my) comment uses pretty clear heading because we were unsure at the time. I fixed the comment. Thanks for pointing it out.

We are lacking Fortran expertise in the core team. We are happy for any help regarding the Fortran bindings and examples.

That makes sense. A compiler that supports F2003 would use the explicit interfaces from the bindings module and make any necessary temporary variables automatically, to “convert” from the arguments passed by reference from Abaqus to the USUB into pass-by-value arguments needed when the USUB calls the C functions. Without the module (i.e. without F2003, which every modern Fortran compiler supports), you would be using implicit interfaces meaning the Fortran compiler would presume all arguments to be passed by reference. Which would cause problems.