Skip to content

Transcribe contents of interpolators_g.F from Fortran to C#160

Closed
mabruzzo wants to merge 14 commits into
grackle-project:mainfrom
mabruzzo:interpolators
Closed

Transcribe contents of interpolators_g.F from Fortran to C#160
mabruzzo wants to merge 14 commits into
grackle-project:mainfrom
mabruzzo:interpolators

Conversation

@mabruzzo

@mabruzzo mabruzzo commented May 27, 2023

Copy link
Copy Markdown
Collaborator

EDIT: I refactored things quite since I first proposed this.1 It's ready to be reviewed now.

This PR is pretty self-explanatory. It transcribes the contents of interpolators_g.F from Fortran to C.

  • The C routines are provided in the newly created interop subdirectory of src/clib
  • Fortran interface files are also provided in that same directory.
  • The README in that directory provides (hopefully clear/useful) instructions for calling these routines from within Fortran routines.
    • There are currently a number of Fortran routines that already do this
    • integrating these new routines into existing routines is easy! You just need to modify the 2 lines that are already in the routine that currently reads
          implicit NONE
      #include "grackle_fortran_types.def"
      and modify the source code so that it now reads
          USE ISO_C_BINDING
          implicit NONE
      #include "grackle_fortran_types.def"
      #include "interop/interop_funcs.def"
      After making this single tweak, the everything "just works"
  • Within src/examples/utest_interpolators I include a number of unit-tests for each interpolator.
    • These unit-tests directly compare the results of the transcribed functions to the original Fortran functions in a number of meaningful test cases
    • For all of the test cases I've come up with (including the test-cases where each interpolator is applied 1,000,000 times using randomly generated inputs), the new C versions produce bitwise identical results.
    • The test-case that makes use of the randomized inputs also serves as a crude benchmark. At -O3 optimizations, all of the C and Fortran versions have extremely comparable performance.
      • For all but one of the functions, the timings of the C and Fortran versions are within ~1% of each other (the version that is faster varies from run-to-run)
      • The only exception here, is interpolate_1d_g. In this case, the C-version of the function appears to consistently be slightly (~5%) faster.
      • After PR [WIP] Introduced CMake based build procedure and first unit/funcitonal tests created #193 is merged, these tests should be consolidated with the other tests (but I don't think we necessarily need to wait)

So to summarize, there is basically no downside to this pull request.

Footnotes

  1. Originally, this was build on top of PR Port calc_temp1d_cloudy_g & cool1d_cloudy_g from Fortran to C #153 (since that was kinda the order in which I originally addressed things). Now PR Port calc_temp1d_cloudy_g & cool1d_cloudy_g from Fortran to C #153 is built on top of this one. This PR is now stand-alone (and it should be reviewed before Port calc_temp1d_cloudy_g & cool1d_cloudy_g from Fortran to C #153). The reason I swapped the order is that PR#153 likely involves a minor performance penalty (although I haven't carefully benchmarked that one)

mabruzzo added a commit to mabruzzo/grackle that referenced this pull request Jul 17, 2024
Description
-----------
Prior to this patch, the ``itmask`` array held elements of the
``logical`` dtype. This patch modified the Fortran layer so that the
variable always has a dtype called ``MASK_TYPE``. In reality,
``MASK_TYPE`` is a macro that expands to ``integer*4`` (the integer-size
was an arbitrary choice).

Motivation
----------
As I previously shared during a development meeting, the usage of the
``logical`` dtype is a bit of an issue for some Fortran->C transcription
efforts. The issue is that:

 * the Fortran specification doesn't define the representation for
   ``.true.`` and ``.false.`` values. Consequently, different
  implementations make different choices (as I understand it, gfortran
   and ifort originally made different choices -- ifort only changed
   their mind in the last 10 years).

 * importantly, this means that there isn't a clear conversion from
   Fortan's ``logical`` dtype and C's dtype. A crude workaround for
   this is to convert from ``logical`` to ``int`` before a Fortran
   function calls a C function.

   * This works fine for a scalar ``logical`` argument (this is what
     gh-grackle-project#160 does).

   * However, it isn't ideal when you have to pass ``logical`` array,
     like ``itmask``, to a C function. You ultimately need to allocate
     a temporary intermediate array and pass it through to the C function
     (as is done by gh-grackle-project#153). This is bad for performance since heap
     memory needs to be freshly allocated/deallocated off the heap during
     each function call. [^1]

By now directly storing integers within ``itmask``, any transcribed C
function now knows how to directly interpret the contents of the array.

Alternative
-----------
The alternative to this patch would to declare ``itmask`` to be a
variable with the type ``logical(kind=c_bool)``, where ``c_bool`` would
be provided by the ``ISO_C_BINDING`` Fortran module (formally, the
module was introduced with Fortran 2003, but all major fortran compilers
support it in other modes). Essentially, this would tell the Fortran
compiler to represent it in the same way as the boolean dtype
introduced to C in 1999 (it was formally called ``_Bool``, but macros
were provided so that you could refer to it as ``bool``).

This alternative would have been less invasive. However, there could be
issues if we ever decided to compile Grackle with a C++ compiler. These
issues could arise because C's ``_Bool`` dtype may not have the same
representation as C++'s ``bool`` dtype (I think this is mostly an issue
when you have compilers provided by different vendors). In order to
support GPUs, Grackle will probably need to start using C++ compilers
(even if we just restrict to the common subset of the language that is
shared with C).

At a previous development meeting, it was decided that the choosen
solution implemented by this patch is preferred.

To Summarize
------------
This patch will allow us to simplify the proposed Fortran->C conversion
in gh-grackle-project#153 (and it will removed performance-overhead of the extra
heap-allocations currently required in the absence of this patch).

In the same way, this patch will **significantly** simplify the process
of converting converting any Fortran functionality that takes an iteration
mask and operates on a slice. This is the vast majority of all grackle
functionality! [^2]

[^1]: Let me be more concrete. In the absence of this patch, gh-grackle-project#153
currently introduces "stub" functions for each transcribed function. Each
"stub" function takes all of the arguments for the transcribed function.
The "stub" function's only purpose is to forward all of the arguments,
other than ``itmask``, directly onto the transcribed function. Instead
of passing ``itmask``, the "stub" function instead passes through a
temporary array that it filled with coerced values from ``itmask``. With
this patch,
allocate a temporary array,
(ii) fills that temporary array
that temporary ``itmask``

[^2]: Aside: gh-grackle-project#160 shows a notable example where this patch isn't
particularly relevant, since that PR converts a set of functions that
only operate on a single value rather than on an array of values.
mabruzzo added a commit to mabruzzo/grackle that referenced this pull request Dec 26, 2024
Unlike other cases where we replaced ``logical`` with ``MASK_TYPE``,
I replaced it with ``integer*8`` for the sake of consistency with the
grackle-project#160 PR (I plan to use the transcription of
interpolators_g.F from that PR in the future).
@mabruzzo

Copy link
Copy Markdown
Collaborator Author

This is now superseded by PR #251

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant