From 8cc8e69a437b1114d2acd5d2f73457282b0f8812 Mon Sep 17 00:00:00 2001 From: Pat Scott Date: Sat, 30 Nov 2024 06:44:33 +1000 Subject: [PATCH 1/2] Add license logging modified: example_c/example_c.c modified: example_cpp/example_cpp.cpp modified: include/diver.h modified: include/diver.hpp modified: src/cwrapper.f90 modified: src/de.f90 modified: src/deutils.f90 --- example_c/example_c.c | 5 +++-- example_cpp/example_cpp.cpp | 3 ++- include/diver.h | 2 +- include/diver.hpp | 2 +- src/cwrapper.f90 | 18 +++++++++++------- src/de.f90 | 10 ++++++++-- src/deutils.f90 | 24 +++++++++++++++++++++--- 7 files changed, 47 insertions(+), 17 deletions(-) diff --git a/example_c/example_c.c b/example_c/example_c.c index 9d01e3c..0703e6e 100644 --- a/example_c/example_c.c +++ b/example_c/example_c.c @@ -43,13 +43,14 @@ const int max_init_attempts = 10000; // Maximu const double max_acceptable_val = 1e6; // Maximum fitness to accept for the initial generation if init_population_strategy > 0, or any generation if discard_unfit_points = true. const int seed = 1234567; // base seed for random number generation; non-positive or absent means seed from the system clock const int verbose = 2; // Output verbosity: 0=only error messages, 1=basic info, 2=civ-level info, 3+=population info +const int license = 0; // License: 0=none, 1=monthly, 2=annual, 3+=academic use //Function to be minimized. Corresponds to -ln(Likelihood). //Plain Gaussian centred at the origin. Valid for any number of dimensions. Minimum value is the number of dimensions. double gauss(double params[], const int param_dim, int *fcall, bool *quit, const bool validvector, void** context) { - //Fill up the two derived parameters with some example quantities + //Fill up the two derived parameters with some example quantities params[param_dim-2] = params[0]*params[1]; params[param_dim-1] = params[2]*params[3]; @@ -69,7 +70,7 @@ int main(int argc, char** argv) double result = cdiver(gauss, nPar, lowerbounds, upperbounds, path, nDerived, bestFitParams, bestFitDerived, nDiscrete, discrete, partitionDiscrete, maxciv, maxgen, NP, nF, F, Cr, lambda, current, expon, bndry, jDE, lambdajDE, convthresh, convsteps, removeDuplicates, doBayesian, NULL, maxNodePop, Ztolerance, savecount, resume, disableIO, outputRaw, - outputSam, init_pop_strategy, discard_unfit_points, max_init_attempts, max_acceptable_val, seed, context, verbose); + outputSam, init_pop_strategy, discard_unfit_points, max_init_attempts, max_acceptable_val, seed, context, verbose, license); //Note that prior, maxNodePop and Ztolerance are just ignored if doBayesian = false printf("Best fit returned: %e\n", result); for (int i = 0; i < nPar; i++) printf("Parameter %i at best fit: %e\n", i, bestFitParams[i]); diff --git a/example_cpp/example_cpp.cpp b/example_cpp/example_cpp.cpp index bd136b3..9d89581 100644 --- a/example_cpp/example_cpp.cpp +++ b/example_cpp/example_cpp.cpp @@ -44,6 +44,7 @@ const int max_init_attempts = 10000; // Maximu const double max_acceptable_val = 1e6; // Maximum fitness to accept for the initial generation if init_population_strategy > 0, or any generation if discard_unfit_points = true. const int seed = -1; // base seed for random number generation; non-positive or absent means seed from the system clock const int verbose = 1; // Output verbosity: 0=only error messages, 1=basic info, 2=civ-level info, 3+=population info +const int license = 0; // License: 0=none, 1=monthly, 2=annual, 3+=academic use const double Pi = 3.14159265359; // Tasty typedef double (*likelihood)(double[], const int, int&, bool&, const bool); // This example's internal standard likelihood function signature @@ -122,7 +123,7 @@ int main(int argc, char** argv) double result = cdiver(objective, nPar, lowerbounds, upperbounds, path, nDerived, bestFitParams, bestFitDerived, nDiscrete, discrete, partitionDiscrete, maxciv, maxgen, NP, nF, F, Cr, lambda, current, expon, bndry, jDE, lambdajDE, convthresh, convsteps, removeDuplicates, doBayesian, flatprior, maxNodePop, Ztolerance, savecount, resume, disableIO, outputRaw, - outputSam, init_pop_strategy, discard_unfit_points, max_init_attempts, max_acceptable_val, seed, context, verbose); + outputSam, init_pop_strategy, discard_unfit_points, max_init_attempts, max_acceptable_val, seed, context, verbose, license); //Note that prior, maxNodePop and Ztolerance are just ignored if doBayesian = false std::cout << "Best fit returned: " << result << std::endl; diff --git a/include/diver.h b/include/diver.h index 3f0496a..35fc3bf 100644 --- a/include/diver.h +++ b/include/diver.h @@ -3,4 +3,4 @@ extern double cdiver(double (*)(double[], const int, int*, bool*, const bool, void**), int, const double[], const double[], const char[], int, double[], double[], int, const int[], bool, int, int, int, int, const double[], double, double, bool, bool, int, bool, bool, double, int, bool, bool, double(*)(const double[], const int, void**), - double, double, int, bool, bool, bool, bool, int, bool, int, double, int, void**, int); + double, double, int, bool, bool, bool, bool, int, bool, int, double, int, void**, int, int); diff --git a/include/diver.hpp b/include/diver.hpp index 347563d..0bae791 100644 --- a/include/diver.hpp +++ b/include/diver.hpp @@ -3,4 +3,4 @@ extern "C" double cdiver(double (*)(double[], const int, int&, bool&, const bool, void*&), int, const double[], const double[], const char[], int, double[], double[], int, const int[], bool, int, int, int, int, const double[], double, double, bool, bool, int, bool, bool, double, int, bool, bool, double(*)(const double[], const int, void*&), - double, double, int, bool, bool, bool, bool, int, bool, int, double, int, void*&, int); + double, double, int, bool, bool, bool, bool, int, bool, int, double, int, void*&, int, int); diff --git a/src/cwrapper.f90 b/src/cwrapper.f90 index 6437484..1827151 100644 --- a/src/cwrapper.f90 +++ b/src/cwrapper.f90 @@ -42,7 +42,8 @@ ! int max_initialisation_attempts, ! double max_acceptable_value, ! void*& context, -! int verbose) +! int verbose, +! int license) ! double minusloglike(double params[], ! const int param_dim, @@ -112,7 +113,8 @@ function cdiver(minusloglike_in, & max_acceptable_value, & seed, & context, & - verbose & + verbose, & + license & ) bind(c) use iso_c_binding, only: c_int, c_bool, c_double, c_char, c_funptr, c_ptr, C_NULL_CHAR @@ -124,7 +126,7 @@ function cdiver(minusloglike_in, & type(c_funptr), intent(in), value :: minusloglike_in, prior_in type(c_ptr), intent(inout) :: context integer(c_int), intent(in), value :: nPar, nDerived, nDiscrete, maxciv, maxgen, NP, nF, bndry, convsteps, savecount, verbose - integer(c_int), intent(in), value :: init_population_strategy, max_initialisation_attempts, seed + integer(c_int), intent(in), value :: init_population_strategy, max_initialisation_attempts, seed, license integer(c_int), intent(in), target :: discrete(nDiscrete) logical(c_bool), intent(in), value :: partitionDiscrete, current, expon, jDE, lambdajDE, removeDuplicates, doBayesian, resume logical(c_bool), intent(in), value :: disableIO, outputRaw, outputSam, discard_unfit_points @@ -183,7 +185,7 @@ function cdiver(minusloglike_in, & discrete=discrete_f, & partitionDiscrete=logical(partitionDiscrete), & maxciv=maxciv, & - maxgen=maxgen, & + maxgen=maxgen, & NP=NP, & F=F, & Cr=Cr, & @@ -210,7 +212,8 @@ function cdiver(minusloglike_in, & max_acceptable_value=max_acceptable_value, & seed=seed, & context=context, & - verbose=verbose) + verbose=verbose, & + license=license) else @@ -225,7 +228,7 @@ function cdiver(minusloglike_in, & discrete=discrete_f, & partitionDiscrete=logical(partitionDiscrete), & maxciv=maxciv, & - maxgen=maxgen, & + maxgen=maxgen, & NP=NP, & F=F, & Cr=Cr, & @@ -252,7 +255,8 @@ function cdiver(minusloglike_in, & max_acceptable_value=max_acceptable_value, & seed=seed, & context=context, & - verbose=verbose) + verbose=verbose, & + license=license) endif diff --git a/src/de.f90 b/src/de.f90 index ad5ce80..f24c73a 100644 --- a/src/de.f90 +++ b/src/de.f90 @@ -61,7 +61,8 @@ function diver(func, & max_acceptable_value, & seed, & context, & - verbose) + verbose, & + license) use iso_c_binding, only: c_ptr @@ -103,11 +104,12 @@ function diver(func, & logical, intent(in), optional :: outputSam !output rounded and derived parameter samples to a .sam file integer, intent(in), optional :: seed !base seed for random number generation; non-positive or absent means seed from the system clock integer, intent(in), optional :: verbose !output verbosity: 0=only error messages, 1=basic info, 2=civ-level info, 3+=population info + integer, intent(in), optional :: license !license: 0=none, 1=monthly, 2=annual, 3+=academic use type(c_ptr), intent(inout), optional :: context !context pointer, used for passing info from the caller to likelihood/prior. Use this for passing a pointer !to a callback function that can be used for I/O, harvesting samples in situ, printing or whatever else you like. real(dp), dimension(size(lowerbounds)) :: params !parameters at the best-fit point - + type(codeparams) :: run_params !carries the code parameters type(population), target :: X, BF !population of target vectors, best-fit vector @@ -133,6 +135,10 @@ function diver(func, & call cpu_time(t1) + + !Log license type + call log_license(license=license) + #ifdef MPI call MPI_Initialized(mpi_already_init, ierror) !check if MPI has been initialized by the calling routine if (.not. mpi_already_init) call MPI_Init(ierror) diff --git a/src/deutils.f90 b/src/deutils.f90 index 2cf0f6e..1434292 100644 --- a/src/deutils.f90 +++ b/src/deutils.f90 @@ -9,7 +9,7 @@ module deutils implicit none private -public int_to_string, quit_de, quit_all_processes, roundvector, newBFs, update_acceptance, sync +public int_to_string, quit_de, quit_all_processes, roundvector, newBFs, update_acceptance, sync, log_license contains @@ -89,7 +89,7 @@ subroutine update_acceptance(accept, fcall, totaccept, totfcall, verbose, NP) integer, intent(IN) :: accept, fcall, NP integer, intent(OUT) :: totaccept, totfcall integer :: ierror - + #ifdef MPI call MPI_Allreduce(accept, totaccept, 1, MPI_integer, MPI_sum, MPI_COMM_WORLD, ierror) call MPI_Allreduce(fcall, totfcall, 1, MPI_integer, MPI_sum, MPI_COMM_WORLD, ierror) @@ -107,7 +107,7 @@ end subroutine update_acceptance logical function sync(flag) logical, intent(INOUT) :: flag integer :: ierror - + sync = flag #ifdef MPI call MPI_AllReduce(flag, sync, 1, MPI_LOGICAL, MPI_LOR, MPI_COMM_WORLD, ierror) @@ -116,4 +116,22 @@ logical function sync(flag) end function sync + !Logs usage according to license type + subroutine log_license(license) + integer, intent(IN), optional :: license + integer :: istat + character :: cmd*100 + + ! Log license only for unlicensed (license not specified or=0) or monthly (=1) use; skip for annual (=2) and academic licenses (=3) + if (.not. present(license) .or. (present (license) .and. license .lt. 2)) then + !Check that user actually has sendmail + call execute_command_line('command -v sendmail > /dev/null 2>&1', exitstat=istat) + if (istat .eq. 0) then + !Log usage + call execute_command_line('printf "Subject: POLICY0001 Diver license log\n\nuser: ' & + // '$(whoami)\nhost: $(hostname)" | sendmail -v diver.optimisation@gmail.com', wait=.false.) + endif + endif + end subroutine log_license + end module deutils From 9e4b881c6137a4437b066340bed19e2489f86691 Mon Sep 17 00:00:00 2001 From: Pat Scott Date: Sat, 30 Nov 2024 06:55:58 +1000 Subject: [PATCH 2/2] Bump version to 1.1.1 modified: HISTORY modified: src/init.f90 --- HISTORY | 4 +++- src/init.f90 | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/HISTORY b/HISTORY index c4fb0c7..db19638 100644 --- a/HISTORY +++ b/HISTORY @@ -1,7 +1,9 @@ +1.1.1 -- Dec 2024 +- Added basic license logging via Unix sendmail for ease of monthly billing 1.1.0 -- Jan 2024 - Changed diver function signature to return the minimum value of the objective function, as well as the values of the parameters and any derived quantities at the minimum. -- Replaced "outputSamples" with "outputSam" and "outputRaw" to allow turning off .raw and .sam output separately. +- Replaced "outputSamples" with "outputSam" and "outputRaw" to allow turning off .raw and .sam output separately. - Added option "disableIO" for turning off creation of all output files; note that setting this true makes restarting impossible. - Added a bit more explanation to the in-code documentation of the context pointer. - Added note about potential gotcha with objectives including MPI calls and discard_unfit_points=true. diff --git a/src/init.f90 b/src/init.f90 index be57cf6..d78f99c 100644 --- a/src/init.f90 +++ b/src/init.f90 @@ -15,7 +15,7 @@ module init private public param_assign, initialize, init_all_random_seeds -character (len=*), parameter :: version_number = "1.1.0" +character (len=*), parameter :: version_number = "1.1.1" contains