Scientific Computing

Fortran character allocatable

Variable length strings are implemented in Fortran 2003 standard like:

character(:), allocatable :: str

Passing such variables to procedures is declared the same as fixed length strings. In fact, we always declare actual arguments with “*” to avoid needing every string an exact length.

subroutine my(str)
character(*), intent(in) :: str

Note that intrinsic Fortran functions need traditional fixed length character variables. For example:

character(1000) :: buf

call get_command_argument(1, buf)

Fortran function can return allocatable characters. If you run into bugs with this on old compilers, try manually allocating the character variable. Fortran standard compliant compilers auto-allocate character functions like numeric arrays.

function greet(b)

logical, intent(in) :: b

character(:), allocatable :: greet

!! Manual allocation of character variable. This could be necessary on old or buggy compilers.

if(b) then
  allocate(character(5) :: greet)
  greet = 'hello'
else
  allocate(character(3) :: greet)
  greet = 'bye'
endif

end function greet

GitHub Actions per-job compiler

GitHub Actions workflows can use different compilers per job. This is useful for programs and libraries that need distinct compiler versions. An example of this is Matlab, where each Matlab release has a range of compatible compilers.

  • Matlab R2021a, R2021b: GCC-8
  • Matlab R2022a, R2022b, R2023a, R2023b: GCC-10

Implement in GitHub Actions:

jobs:

  linux:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        release: [R2021b, R2024a, latest-including-prerelease]

    steps:

    - name: GCC-8 (Matlab < R2022a)
      if: ${{ matrix.release < 'R2022a' && matrix.release != 'latest-including-prerelease' }}
      run: |
        echo "CC=gcc-8" >> $GITHUB_ENV
        echo "CXX=g++-8" >> $GITHUB_ENV
        echo "FC=gfortran-8" >> $GITHUB_ENV        

    - name: GCC-10 (Matlab >= R2022a)
      if: ${{ matrix.release >= 'R2022a' || matrix.release == 'latest-including-prerelease' }}
      run: |
        echo "CC=gcc-10" >> $GITHUB_ENV
        echo "CXX=g++-10" >> $GITHUB_ENV
        echo "FC=gfortran-10" >> $GITHUB_ENV        

    - name: Install MATLAB
      uses: matlab-actions/setup-matlab
      with:
        release: ${{ matrix.release }}

Enable Windows battery time on hover

Battery time remaining estimates for computing devices can vary widely in accuracy. The estimates are based on assumptions about future behavior based on prior usage trends, from a mix of current and prior charge usage. Windows updates can disable battery time remaining, and devices may come from the factory with battery time estimates disabled.

Hovering over the battery icon on the Windows taskbar can show the estimated battery time remaining along with the percent battery charge. The estimated battery time remaining is the same shown under System / Power & Battery.

The usual precautions on modifying the Windows Registry apply–do a Windows System Recovery milestone first. These keys are under:

HKLM\SYSTEM\CurrentControlSet\Control\Power

Reboot after making these changes. It may take a minute or two after first reboot for the estaimted battery life to show up.

If these registry keys exist, set their value to 0. If they don’t exist, that’s fine too.

EnergyEstimationDisabled=0
UserBatteryDischargeEstimator=0

Create this DWORD32 value (if not existing) and set to 1

EnergyEstimationEnabled=1

Reference: forum

CMake JSON array iteration

JSON can hold several data types including arrays. This example iterates over a JSON array in CMake.

Suppose file “json.cmake” contains:

cmake_minimum_required(VERSION 3.19)

set(jarr "{
\"c\":[3,4,5]
}")

string(JSON L LENGTH ${jarr} "c")
math(EXPR L "${L}-1")

string(JSON t TYPE ${jarr} "c")
message(STATUS "type: ${t}")

foreach(i RANGE ${L})
  string(JSON v GET ${jarr} "c" ${i})
  string(JSON t TYPE ${jarr} "c" ${i})
  message(STATUS "c[${i}] = ${v}  ${t}")
endforeach()

This results in:

$ cmake -P json.cmake

-- type: ARRAY
-- c[0] = 3  NUMBER
-- c[1] = 4  NUMBER
-- c[2] = 5  NUMBER

GDB debugger for macOS Apple Silicon

GDB debugger is not yet readily available for macOS with Apple Silicon CPU. It has long been possible to use a virtual machine with Linux for ARM64 to run GDB within the VM. The CLion package provides GDB, but with caveats such as using a particular compiler and libstdc++. What happens for us is when trying to use GDB, it doesn’t work:

gdb ./myexe
r

Don’t know how to run. Try “help target”.

In general, currently to use GDB on an Apple Silicon Mac, it seems a Linux VM is the best option–hopefully this changes.

Easy HDF5 / NetCDF4 / HDF4 Matlab interface

Using HDF5 / NetCDF4 / HDF4 from any language can be intimidating if directly using the low-level API. Interfaces have sprung up for popular languages that make HDF5 trivially easy to use, such as Python h5py.

The stdlib for Matlab provides functions making HDF5, NetCDF4, and HDF4 much easier to use in Matlab.

The “h5*” functions are for HDF5, “nc*” functions are for NetCDF4, and “h4*” functions are for HDF4. The functions are polymorphic, typecasting user data.

The h5*, nc*, and h4* functions work very similarly. For simplicity, we only show the h5* functions.

  • h5save() save a variable to a file
  • h5variables() list all the variable in a file
  • h5size() get the size (shape) of a variable in a file
  • h5exists() check if a variable exists in a file

C macro __CLASSIC_C__

The C macro __CLASSIC_C__ is defined when the compiler is in pre-ANSI (K&R) mode. This is a rather uncommon scenario. It might be used in retrocomputing with very old and unmaintained compilers such as the 1990s Bruce Evans’ C compiler (bcc).

#include <stdio.h>

int main() {

#if defined(__CLASSIC_C__)
  printf("K&R C\n");
#elif defined(__STDC__)
  printf("ANSI C\n");
#else
  printf("Unknown C\n");
#endif

return 0;
}

Reference: Compiler Macros wiki

Windows Command Prompt instant error on open

A botched program install, upgrade, or uninstall such as Anaconda Python can make a Windows registry mis-entry that causes many commands to fail. Simply trying to run “cmd.exe” COMSPEC instantly fails with:

& was unexpected at this time

or

Process exited with code 1

If this message occurs when just opening a new Command Prompt window, the problem may be in the Windows Registry. Check Registry Editor values:

HKCU\Software\Microsoft\Command Processor\AutoRun

and

HKLM\Software\Microsoft\Command Processor\AutoRun

Example 1

A system had a bad Autorun value:

if exist

This was corrected by emptying the Autorun value (or deleting the Autorun key).

Example 2

A system had a bad Autorun value:

if exist & if exist "%USERPROFILE%\miniconda3\condabin\conda_hook.bat" "%USERPROFILE%\miniconda3\condabin\conda_hook.bat"

It was fixed by correcting to:

if exist "%USERPROFILE%\miniconda3\condabin\conda_hook.bat" "%USERPROFILE%\miniconda3\condabin\conda_hook.bat"

C++ nodiscard attribute

C++17 and C23 added the [[nodiscard]] attribute to indicate that the result of a function call should not be ignored. However, a C++26 proposal to remove [[nodiscard]] from the language standard is under consideration.

Example: annotate function declaration in the header file with [[nodiscard]] attribute.

[[nodiscard]] int one();
int one() { return 1; }

GNU Data Language (GDL) GUI

GNU Data Language (GDL) can use GDLDE Workbench GUI for graphical development.

Download and install GDL.

The Windows installer includes GDLDE Workbench: gdlsetup-Windows-x86_64-standard.exe Simply install and look in Windows Start menu for “GDL Workbench”.

For macOS use gdl-macOS-x86_64-standard.dmg or build GDL from source.

For Ubuntu Linux:

apt install gnudatalanguage

Download and extract GDLDE for Linux.