sim_db for Fortran

Minimal Example using Fortran

A parameter file called params_mininal_fortran_example.txt is located in the sim_db/examples/ directory in the source code. The file contains the following:

name (string): minimal_fortran_example

{cmake_config} (alias): cmake -Hroot/ -Broot/examples/build -DFortran=ON
{cmake_build} (alias): {cmake_config}; cmake --build root/examples/build --target

run_command (string): {cmake_build} minimal_fortran_example; root/examples/build/minimal_fortran_example

param1 (string): "Minimal Fortran example is running."

param2 (int): 42

A Fortran file called minimal_example.f90 and is found in the same directory:

program minimal_example
    use sim_db_mod
    implicit none

    type(sim_db) :: sim_database
    character(len=:), allocatable :: param1
    integer :: param2

    ! Open database and write some initial metadata to database.
    sim_database = sim_db()

    ! Read parameters from database.
    call sim_database%read("param1", param1)
    call sim_database%read("param2", param2)

    ! Demonstrate that the simulation is running.
    print *, param1

    ! Write final metadata to database and close connection.
    call sim_database%close()
end program minimal_example

Add the those simulations parameters to the sim_db database and run the simulation from within the sim_db/examples directory with:

$ sim_db add_and_run -f params_minimal_cpp_example.txt

Notice that when it is run, it first call two cmake commands to compile the code if needed. What cmake does is equvalient to the following command called from sim_db/examples/ (given that the static Fortran library are compiled and located in sim_db/build):

$ gfortran -o build/minimal_fortran_example minimal_example.f90 -I../build -L../build -lsimdbf -lpthread -ldl -m

The example is not really a minimal one. If you already have compiled your program into a executable called program located in the current directory, the lines starting with {...} (alias): can be removed and the run_command can be replaced with simpy run_command (string): ./program.

Extensive Example using Fortran

A parameter file called params_extensive_cpp_example.txt is found in the sim_db/examples/ directory in the source code. This parameter file contains all the possible types available in addition to some comments:

This is a comment, as any line without a colon is a comment.
# Adding a hashtag to the start of a comment line, make the comment easier to recognize.

# The name parameter is highly recommended to include.
name (string): extensive_fortran_example

# It is also recommended to include a description to further explain the intention of 
# the simulation.
description (string): Extensive Fortran example to demonstrate most features in sim_db.

# Aliases for cmake commands for compiling the example. 
{cmake_config} (alias): cmake -Hroot/ -Broot/examples/build -DFortran=ON
{cmake_build} (alias): {cmake_config}; cmake --build root/examples/build --target

# This 'run_command' starts with an alias that is replaced with the above two cmake 
# commands that compile the extensitve example if needed. The last part of the 
# 'run_command' then run the compiled example. Each command is seperated by a 
# semicolon, but they all need to be on the same line.
run_command (string): {cmake_build} extensive_fortran_example; root/examples/build/extensive_fortran_example

# A parameter is added for each of the avaiable types.
param1_extensive (int): 3
param2_extensive (float): -0.5e10
param3_extensive (string): "Extensive C++ example is running."
param4_extensive (bool): True
param5_extensive (int array): [1, 2, 3]
param6_extensive (float array): [1.5, 2.5, 3.5]
param7_extensive (string array): ["a", "b", "c"]
param8_extensive (bool array): [True, False, True]

# Include parameters from another parameter file.
include_parameter_file: root/examples/extra_params_example.txt

# Change a parameter value from the included parameter file to demonstrate that
# it is the last parameter value that count for a given parameter name. 
extra_param1 (int): 9

The line in the parameter file starting with include_parameter_file: will be substituted with the contain of the specified extra_params_example.txt file, found in the same directory:

# Extra parameters included in the extensive examples.

extra_param1 (int): 7
extra_param2 (string): "Extra params added."
extra_param3 (bool): False

extensive_example.py is also found in the same directory:

program extensive_example
    use sim_db_mod
    implicit none
    
    type(sim_db) :: sim_database, sim_database_2
    integer :: param1, i, id
    real :: param2
    real(kind=kind(1.0d0)) :: param2_dp
    character(len=:), allocatable :: param3, name_results_dir, path_proj_root
    logical :: param4, is_column_in_database, is_empty
    integer, dimension(:), allocatable :: param5
    real, dimension(:), allocatable :: param6
    real(kind=kind(1.0d0)), dimension(:), allocatable :: param6_dp
    character(len=:), dimension(:), allocatable :: param7
    logical, dimension(:), allocatable :: param8

    ! Open database and write some inital metadata to database.
    sim_database = sim_db()

    ! Read parameters from database.
    call sim_database%read("param1_extensive", param1)
    call sim_database%read("param2_extensive", param2)
    call sim_database%read("param2_extensive", param2_dp)
    call sim_database%read("param3_extensive", param3)
    call sim_database%read("param4_extensive", param4)
    call sim_database%read("param5_extensive", param5)
    call sim_database%read("param6_extensive", param6)
    call sim_database%read("param6_extensive", param6_dp)
    call sim_database%read_string_array("param7_extensive", param7)
    call sim_database%read("param8_extensive", param8)

    ! Demostrate that the simulation is running.
    print *, param3

    ! Write all the possible types to database.
    ! Only these types are can be written to the database.
    call sim_database%write("example_result_1", param1)
    call sim_database%write("example_result_2", param2)
    call sim_database%write("example_result_2", param2_dp)
    call sim_database%write("example_result_3", param3)
    call sim_database%write("example_result_4", param4)
    call sim_database%write("example_result_5", param5)
    call sim_database%write("example_result_6", param6)
    call sim_database%write("example_result_6", param6_dp)
    call sim_database%write("example_result_7", param7)
    call sim_database%write("example_result_8", param8)


    ! Make unique subdirectory for storing results and write its name to
    ! database. Large results are recommended to be saved in this subdirectory.
    name_results_dir = sim_database%unique_results_dir("root/examples/results")

    ! Write some results to a file in the newly create subdirectory.
    open(1, file=name_results_dir // "/results.txt")
    do i = 1, size(param6)
        write (1,*) param6(i) 
    end do

    ! Check if column exists in database.
    is_column_in_database = sim_database%column_exists("column_not_in_database")

    ! Check if column is empty and then set it to empty.
    is_empty = sim_database%is_empty("example_results_1")
    call sim_database%set_empty("example_result_1")

    ! Get the 'ID' of the connected simulation an the path to the project's
    ! root directory.
    id = sim_database%get_id()
    path_proj_root = sim_database%get_path_proj_root()

    ! Add an empty simulation to the database, open connection and write to it.
    sim_database_2 = sim_db_add_empty_sim(path_proj_root);
    call sim_database_2%write("param1_extensive", 7)

    ! Delete simulation from database.
    call sim_database_2%delete_from_database()

    ! Write final metadata to database and close connection.
    ! (Final method (destructor) is not called at end of program, so close()
    !  MUST be called manually. It is always recommended to call close()
    !  explicitly to avoid unexpected, because of this.)
    call sim_database%close()
end program extensive_example

Add the those simulations parameters to the sim_db database and run the simulation from within the sim_db/examples directory with:

$ sdb add_and_run -f params_extensive_fortran_example.txt

Notice that when it is run, it first call cmake to compile the code if needed. What cmake does is equvalient to the following command called from sim_db/examples/ (given that the static Fortran library are compiled and located in sim_db/build/):

$ gfortran -o build/extensive_fortran_example extensive_example.f90 -I../build -L../build -lsimdbf -lpthread -ldl -m

Fortran API Referance

Doxygen and Breathe that is used to generate the documentation for C, C++ and Fortran, does not work as well for Fortran as it does for C and C++. The Fortran documentation is therefor less than ideal, but hopefully still somewhat useful, espesially in combination with the examples. The parameter types are written in bold at the start of the parameter description.

interface sim_db

Class to interact with the sim_db database.

Constructor is an overload of the sim_db_dtor* functions below, which gives the valid types of parameters.

Should be called at the very begin of the simulation and close should be called at the very end to add the correct metadata and to clean up.

For multithreading/multiprocessing each thread/process MUST have its own connection (instance of this class).

type(sim_db) function sim_db_mod::sim_db_ctor (store_metadata)

Connect to the database using the command line arguments containing --id 'ID' and optionally --path_proj_root 'PATH'. PATH is the root directory of the project, where *.sim_db/* is located. If not passed, the current working directory and its parent directories will be searched until *.sim_db/* is found.

Parameters
  • store_metadata: logical, optional Stores metadata to database if true. Set to ‘false’ for postprocessing (e.g. visualization) of data from simulation.

type(sim_db) function sim_db_mod::sim_db_ctor_with_id (id, store_metadata)

Parameters
  • id: integer, intent(in) ID number of the simulation paramters in the sim_db database.

  • store_metadata: logical, optional Stores metadata to database if true. Set to ‘false’ for postprocessing (e.g. visualization) of data from simulation.

type(sim_db) function sim_db_mod::sim_db_ctor_without_search (path_proj_root, id, store_metadata)

Parameters
  • path_proj_root: character(len=*), intent(in) Path to the root directory of the project, where *.sim_db/* is located.

  • id: integer, intent(in) ID number of the simulation paramters in the sim_db database.

  • store_metadata: logical, optional Stores metadata to database if true. Set to ‘false’ for postprocessing (e.g. visualization) of data from simulation.

generic sim_db_mod::sim_db::read => read_int, read_real_sp, read_real_dp, read_string, read_logical, read_int_array, read_real_sp_array, read_real_dp_array, read_string_array, read_logical_array

Read parameter from database.

Overload of the read_* subroutines below, which gives the valid types of parameters.

subroutine sim_db_mod::read_int(self, column, int_value)

Parameters
  • [in] column: character(len=*), intent(in) Name of the parameter and column in the database.

  • [out] int_value: integer, intent(out) Value read from database.

subroutine sim_db_mod::read_real_sp(self, column, real_value)

Parameters
  • [in] column: character(len=*), intent(in) Name of the parameter and column in the database.

  • [out] real_value: real, intent(out) Value read from database.

subroutine sim_db_mod::read_real_dp(self, column, real_value)

Parameters
  • [in] column: character(len=*), intent(in) Name of the parameter and column in the database.

  • [out] real_value: real(kind=kind(1.0d0)), intent(out) Value read from database.

subroutine sim_db_mod::read_string(self, column, string_value)

Parameters
  • [in] column: character(len=*), intent(in) Name of the parameter and column in the database.

  • [out] string_value: character(len=:), allocatable, intent(out) Value read from database.

subroutine sim_db_mod::read_logical(self, column, logical_value)

Parameters
  • [in] column: character(len=*), intent(in) Name of the parameter and column in the database.

  • [out] logical_value: logical, intent(out) Value read from database.

subroutine sim_db_mod::read_int_array(self, column, int_array)

Parameters
  • [in] column: character(len=*), intent(in) Name of the parameter and column in the database.

  • [out] int_array: integer, dimension(:), allocatable, intent(out) Value read from database.

subroutine sim_db_mod::read_real_sp_array(self, column, real_array)

Parameters
  • [in] column: character(len=*), intent(in) Name of the parameter and column in the database.

  • [out] real_array: real, dimension(:), allocatable, intent(out) Value read from database.

subroutine sim_db_mod::read_real_dp_array(self, column, real_array)

Parameters
  • [in] column: character(len=*), intent(in) Name of the parameter and column in the database.

  • [out] real_array: real(kind=kind(1.0d0)), dimension(:), allocatable, intent(out) Value read from database.

subroutine sim_db_mod::read_string_array(self, column, string_array)

Parameters
  • [in] column: character(len=*), intent(in) Name of the parameter and column in the database.

  • [out] **allocatable[out] intent(out): :: string_array character(len(:), dimension(** Value read from databas.

subroutine sim_db_mod::read_logical_array(self, column, logical_array)

Parameters
  • [in] column: character(len=*), intent(in) Name of the parameter and column in the database.

  • [out] logical_array: logical, dimension(:), allocatable, intent(out) Value read from database.

generic sim_db_mod::sim_db::write => write_int, write_real_sp, write_real_dp, write_string, write_logical, write_int_array, write_real_sp_array, write_real_dp_array, write_string_array, write_logical_array, write_int_false, write_real_sp_false, write_real_dp_false, write_string_false, write_logical_false, write_int_array_false, write_real_sp_array_false, write_real_dp_array_false, write_string_array_false, write_logical_array_false

Write parameter to database.

Overload of the write_* below, which gives the valid types of parameters.

subroutine sim_db_mod::write_int(self, column, int_value, only_if_empty)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • int_value: integer, intent(in) To be written to database.

  • only_if_empty: logical If .true., it will only write to the database if the simulation’s entry under ‘column’ is empty. Will avoid potential timeouts for concurrect applications.

subroutine sim_db_mod::write_int_false(self, column, int_value)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • int_value: integer, intent(in) To be written to database.

subroutine sim_db_mod::write_real_sp(self, column, real_value, only_if_empty)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • real_value: real, intent(in) To be written to database.

  • only_if_empty: logical If .true., it will only write to the database if the simulation’s entry under ‘column’ is empty. Will avoid potential timeouts for concurrect applications.

subroutine sim_db_mod::write_real_sp_false(self, column, real_value)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • real_value: real, intent(in) To be written to database.

subroutine sim_db_mod::write_real_dp(self, column, real_value, only_if_empty)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • real_value: real(kind=kind(1.0d0)), intent(in) To be written to database.

  • only_if_empty: logical If .true., it will only write to the database if the simulation’s entry under ‘column’ is empty. Will avoid potential timeouts for concurrect applications.

subroutine sim_db_mod::write_real_dp_false(self, column, real_value)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • real_value: real(kind=kind(1.0d0)), intent(in) To be written to database.

subroutine sim_db_mod::write_string(self, column, string_value, only_if_empty)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • string_value: character(len=*), intent(in) To be written to database.

  • only_if_empty: logical If .true., it will only write to the database if the simulation’s entry under ‘column’ is empty. Will avoid potential timeouts for concurrect applications.

subroutine sim_db_mod::write_string_false(self, column, string_value)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • string_value: character(len=*), intent(in) To be written to database.

subroutine sim_db_mod::write_logical(self, column, logical_value, only_if_empty)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • logical_value: logical, intent(in) To be written to database.

  • only_if_empty: logical If .true., it will only write to the database if the simulation’s entry under ‘column’ is empty. Will avoid potential timeouts for concurrect applications.

subroutine sim_db_mod::write_logical_false(self, column, logical_value)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • logical_value: logical, intent(in) To be written to database.

subroutine sim_db_mod::write_int_array(self, column, int_array, only_if_empty)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • int_array: integer, dimension(:), intent(in) To be written to database.

  • only_if_empty: logical If .true., it will only write to the database if the simulation’s entry under ‘column’ is empty. Will avoid potential timeouts for concurrect applications.

subroutine sim_db_mod::write_int_array_false(self, column, int_array)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • int_array: integer, dimension(:), target, intent(in) To be written to database.

subroutine sim_db_mod::write_real_sp_array(self, column, real_array, only_if_empty)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • real_array: real, dimension(:), intent(in) To be written to database.

  • only_if_empty: logical If .true., it will only write to the database if the simulation’s entry under ‘column’ is empty. Will avoid potential timeouts for concurrect applications.

subroutine sim_db_mod::write_real_sp_array_false(self, column, real_array)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • real_array: real, dimension(:), intent(in) To be written to database.

subroutine sim_db_mod::write_real_dp_array(self, column, real_array, only_if_empty)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • real_array: real(kind=kind(1.0d0)), dimension(:), intent(in) To be written to database.

  • only_if_empty: logical If .true., it will only write to the database if the simulation’s entry under ‘column’ is empty. Will avoid potential timeouts for concurrect applications.

subroutine sim_db_mod::write_real_dp_array_false(self, column, real_array)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • real_array: real(kind=kind(1.0d0)), dimension(:), target, intent(in) To be written to database.

subroutine sim_db_mod::write_string_array(self, column, string_array, only_if_empty)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • string_array: character(len=*), dimension(:), intent(in) n=*), dimension**(To be written to database.

  • only_if_empty: logical If .true., it will only write to the database if the simulation’s entry under ‘column’ is empty. Will avoid potential timeouts for concurrect applications.

subroutine sim_db_mod::write_string_array_false(self, column, string_array)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • intent: character(len=*), dimension(To be written to database.

subroutine sim_db_mod::write_logical_array(self, column, logical_array, only_if_empty)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • logical_array: logical, dimension(:), intent(in) To be written to database.

  • only_if_empty: logical If .true., it will only write to the database if the simulation’s entry under ‘column’ is empty. Will avoid potential timeouts for concurrect applications.

subroutine sim_db_mod::write_logical_array_false(self, column, logical_array)

Parameters
  • column: character(len=*), intent(in) Name of the parameter and column in the database.

  • logical_array: logical, dimension(:), intent(in) To be written to database.

character(len=:) function, allocatable sim_db_mod::unique_results_dir (self, path_to_dir)

Get path to subdirectory in path_directory unique to simulation.

The subdirectory will be named ‘date_time_name_id’ and is intended to store results in. If ‘results_dir’ in the database is empty, a new and unique directory is created and the path stored in ‘results_dir’. Otherwise the path in ‘results_dir’ is just returned.

Return

character(len=:), allocatable Path to new subdirectory.

Parameters
  • path_directory: character(len=*), intent(in) Path to where the new directory is created. If it starts with ‘root/’, that part will be replaced with the full path to the root directory of the project.

character(len=:) function, allocatable sim_db_mod::unique_results_dir (self, path_to_dir)

Get path to subdirectory in path_directory unique to simulation.

The subdirectory will be named ‘date_time_name_id’ and is intended to store results in. If ‘results_dir’ in the database is empty, a new and unique directory is created and the path stored in ‘results_dir’. Otherwise the path in ‘results_dir’ is just returned.

Return

character(len=:), allocatable Path to new subdirectory.

Parameters
  • path_directory: character(len=*), intent(in) Path to where the new directory is created. If it starts with ‘root/’, that part will be replaced with the full path to the root directory of the project.

character(len=:) function, allocatable sim_db_mod::unique_results_dir_abs_path (self, abs_path_to_dir)

Get path to subdirectory in abs_path_to_dir unique to simulation.

The subdirectory will be named ‘date_time_name_id’ and is intended to store results in. If ‘results_dir’ in the database is empty, a new and unique directory is created and the path stored in ‘results_dir’. Otherwise the path in ‘results_dir’ is just returned.

Return

character(len=:), allocatable Path to new subdirectory.

Parameters
  • abs_path_to_dir: character(len=*), intent(in) Absolute path to where the new directory is created.

logical function sim_db_mod::column_exists (self, column)

Return true if column is a column in the database.

Parameters
  • column: character(len=*), intent(in) Name of column in database.

logical function sim_db_mod::is_empty (self, column)

Return true if entry in database under column is empty.

Parameters
  • column: character(len=*), intent(in) Name of column in database.

subroutine sim_db_mod::set_empty(self, column)

Set entry under column in database to empty.

Parameters
  • column: character(len=*), intent(in) Name of column in database.

integer function sim_db_mod::get_id (self)

Return ID number of simulation in the database that is connected.

character(len=:) function, allocatable sim_db_mod::get_path_proj_root (self)

Return path to root directory of the project, where *.sim_db/* is located.

generic sim_db_mod::sim_db::update_sha1_executables => update_sha1_executables_conditionally, update_sha1_executables_unconditionally

Save the sha1 hash of the files paths_executables to the database.

Overload of the update_sha1_executables_* functions, which gives the valid types of parameters.

subroutine sim_db_mod::update_sha1_executables_conditionally(self, paths_executables, only_if_empty)

Parameters
  • paths_executables: character(len=:), dimension(:), allocatable, intent(in) Paths to executable files.

  • len: Length of paths_executables.

  • <strong>logicalintent(in)</strong>: only_if_empty If True, it will only write to the database if the simulation’s entry under ‘sha1_executables’ is empty. Will avoid any potential timeouts for concurrect applications.

subroutine sim_db_mod::update_sha1_executables_unconditionally(self, paths_executables)

Parameters
  • paths_executables: character(len=:), dimension(:), allocatable, intent(in) Paths to executable files.

  • len: Length of paths_executables.

subroutine sim_db_mod::allow_timeouts(self, is_allowing_timeouts)

Allow timeouts to occure without exiting if set to true.

A timeout occures after waiting more than 5 seconds to access the database because other threads/processes are busy writing to it. sim_db will exit with an error in that case, unless allow timeouts is set to true. It is false by default. If allowed and a timeout occures the called funciton will have had no effect.

logical function sim_db_mod::have_timed_out (self)

Checks if a timeout have occured since last call to this function.

subroutine sim_db_mod::delete_from_database(self)

Delete simulation from database.

subroutine sim_db_mod::close(self)

Add metadate for ‘used_walltime’ to database and update ‘status’ to ‘finished’ and cleans up.