Matlab cURL instead of websave

Matlab websave might not work in cases where a plain “curl” or “wget” command works. A symptom of this issue is HTML is downloaded instead of the intended binary file. Websites such as Dropbox recognize the HTTP User Agent of cURL and Wget and mutate the web server response to be automation-friendly. Since Matlab is much less commonly used than Python, cURL, Wget, etc. this user agent-dependent behavior results. We recommend understanding why Matlab websave doesn’t work, or use the low-level Matlab HTTP Interface.


If you truly need to use cURL from Matlab, recognize this may require unique setup for each system, despite that cURL is included (preinstalled) in modern operating systems including Windows.

The extra quotes around “url” allow for arbitrary characters to be used in the URL that can confuse shells like zsh. The “-L” option to cURL allows redirects.

function curlsave(filename, url)

cmd = "curl -L -o " + filename + " '" + url + "'";

assert(system(cmd) == 0, "download failed: " + url)

end

Linux systems with multiple cURL versions installed may need to set an environment variable to prioritize. Set the filename as appropriate for computer (ensure the file exists).

export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libcurl.so.4

Even this doesn’t always work, so we recommend understanding why Matlab websave doesn’t work, or use the low-level Matlab HTTP Interface.

Matlab with GitHub Actions CI

Matlab CI services include GitHub Actions. Matlab GitHub Actions CI is useful to automatically unit test Matlab code on each “git push” as with other coding languages. As with other GitHub Actions workflows, use a file like “.github/workflows/ci_matlab.yml” file in the Git repo to control CI behavior. A top-level file named like “TestAll.m” is also needed to control the CI run.

This Matlab .github/workflows/ci_matlab.yml will test a Matlab project on GitHub Actions CI at no cost. The top level TestAll.m is also necessary to discover and run the tests.

We have several projects using GitHub Actions with Matlab in this manner.

CMake generate Fortran from template

CMake configure_file can serve to generate source code files including Fortran. For templates beyond a few lines of code, it may be useful to read the template from a file. This requires setting CMake directory property CMAKE_CONFIGURE_DEPENDS to have CMake regenerate the file if the template file changes as in the example below.

file(READ my_template.in.f90 template_code)
configure_file(my.in.f90 my.f90 @ONLY)

set_directory_properties(PROPERTIES CMAKE_CONFIGURE_DEPENDS my_template.in.f90)

#example use
add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/my.f90)

CTest parallel run by default

CMake environment variable CTEST_PARALLEL_LEVEL can be manually set to control default test parallel runs. It’s often desired to run tests in parallel to save time, and help ensure there aren’t hidden dependencies between tests. That is because CTest when run in parallel will effectively randomize the order of the tests, while maintaining dependencies setup by CTest fixtures. We usually set CTEST_PARALLEL_LEVEL environment variable to be equal to the number of physical CPU cores as a starting point.

If the computer runs out of RAM or has conflicts with parallel tests, then use Resource Locks and/or Fixtures to control the parallelism on a per-test basis.

iftop config file

iftop is a handy utility on MacOS, Linux and other Unices for a live Terminal graph of network data flow to particular addresses. On computers with many network interfaces, including virtual interfaces such as on MacOS, it is handy to set a default interface in a config file. iftop uses the file ~/.iftoprc.

For example, on MacOS you may be interested in interface “en1”. To help determine the desired interface, use ifconfig or ip a to find the interface with the public IP address. Then create ~/.iftoprc containing like:

interface: en1

where “en1” is your desired interface determined as per above.

ctest_empty_binary_directory usage

CTest CDash scripts can use the function ctest_empty_binary_directory to recursively remove a CMake build directory to avoid hidden state between test runs in an overall build-test cycle. However, this function will cause the overall CTest run to return a non-zero error code if CMakeCache.txt isn’t present in the build directory. This is confusing in a CI system particularly. While we do appreciate this safety feature over simply using file(REMOVE_RECURSE), it’s necessary to enclose in if() statements like below to avoid false errors. Here we assume you have already set CTEST_MODEL.

if(CTEST_MODEL STREQUAL Nightly OR CTEST_MODEL STREQUAL Continuous)
  if(EXISTS ${CTEST_BINARY_DIRECTORY}/CMakeCache.txt)
    ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY})
  endif()
endif()

...

ctest_start(${CTEST_MODEL})

...

Red Hat firewalld port add

Red Hat / CentOS uses firewalld to provide network firewall. firewalld has the concept of runtime vs. permanent rules, which help avoid getting the firewall into an unusable state. Permanent rules become live at next restart/reboot, while runtime rules disappear at restart/reboot.

Suppose one wishes to put the SSH server on a non-default port 12345 to mitigate auth log clutter. First configure the SSH server in /etc/ssh/sshd_config, then restart SSH and verify the SSH configuration is working by adding your port to firewalld (here, 12345):

firewall-cmd --add-port=12345/tcp

If this works, make the firewalld rule permanent:

firewall-cmd --permanent --add-port=12345/tcp

SELinux will also need an updated policy to allow the SSH port change, like:

sudo semanage port -a -t ssh_port_t -p tcp 12345

Use modern compilers in CentOS

Often we need a more modern compiler than is included in Red Hat / CentOS for HPC systems. Once an admin sets up GCC Toolset they can be loaded by any user thereafter. Prior to CentOS / RHEL 8, this was known as Developer Toolset devtoolset. CentOS / RHEL 8 introduced GCC Toolsets.

For example, to install and use GFortran 10, have the system admin do:

yum install gcc-toolset-10-gcc-gfortran

Thereafter, users without sudo use the new Gfortran version by:

scl enable gcc-toolset-10 bash

which is for that Terminal session only.

Fortran contiguous variables

Fortran 2018 contiguous arrays build upon Fortran 2008. In general, operating on contiguous arrays is faster than non-contiguous arrays. A non-contiguous array actual argument into a contiguous subroutine dummy argument is incorrect syntax. GCC < 9 may fail with SIGSEGV or SIGABRT in this case, dependent on array size. Other compiler correct this incorrect syntax by temporary array copy-in, copy-out which is slower.

Contiguous variables happen by default, so unless you do something with pointers or array striding, the variable is likely to be contiguous for simple Fortran code. To be sure, use is_contiguous intrinsic function. GCC ≥ 9 has is_contiguous and so do other modern Fortran compilers.


References: Fortran 2008 Contiguity

CMake expanduser tilde ~

To have the most reliable path operations in CMake, it’s typically best to resolve paths to the full expanded path. Note: there are a few CMake functions that desire relative paths, but those are clearly spelled out in the docs.

We have created expanduser.cmake:


Related: CMake file separator