From 3a3342f033fd2330f4e375f80b9fb924fa6b0687 Mon Sep 17 00:00:00 2001
From: "Peter W. Draper" <p.w.draper@durham.ac.uk>
Date: Fri, 16 Jun 2017 16:17:34 +0100
Subject: [PATCH] Add -P command-line option to overwrite or add program
 parameters without modifying the YML file, useful for quick tests

---
 examples/main.c | 17 ++++++++++++++-
 src/parser.c    | 58 ++++++++++++++++++++++++++++++++++++++++++++++++-
 src/parser.h    |  2 ++
 3 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/examples/main.c b/examples/main.c
index 631117148a..f4425cb797 100644
--- a/examples/main.c
+++ b/examples/main.c
@@ -87,6 +87,8 @@ void print_help_message() {
   printf("  %2s %8s %s\n", "-n", "{int}",
          "Execute a fixed number of time steps. When unset use the time_end "
          "parameter to stop.");
+  printf("  %2s %8s %s\n", "-P", "{sec:par:val}",
+         "Set parameter value, can be used more than once.");
   printf("  %2s %8s %s\n", "-s", "", "Run with hydrodynamics.");
   printf("  %2s %8s %s\n", "-S", "", "Run with stars.");
   printf("  %2s %8s %s\n", "-t", "{int}",
@@ -170,12 +172,14 @@ int main(int argc, char *argv[]) {
   int verbose = 0;
   int nr_threads = 1;
   int with_verbose_timers = 0;
+  int nparams = 0;
+  char *cmdparams[PARSER_MAX_NO_OF_PARAMS];
   char paramFileName[200] = "";
   unsigned long long cpufreq = 0;
 
   /* Parse the parameters */
   int c;
-  while ((c = getopt(argc, argv, "acCdDef:FgGhMn:sSt:Tv:y:")) != -1)
+  while ((c = getopt(argc, argv, "acCdDef:FgGhMn:P:sSt:Tv:y:")) != -1)
     switch (c) {
       case 'a':
         with_aff = 1;
@@ -224,6 +228,10 @@ int main(int argc, char *argv[]) {
           return 1;
         }
         break;
+      case 'P':
+        cmdparams[nparams] = optarg;
+        nparams++;
+        break;
       case 's':
         with_hydro = 1;
         break;
@@ -351,6 +359,13 @@ int main(int argc, char *argv[]) {
   if (myrank == 0) {
     message("Reading runtime parameters from file '%s'", paramFileName);
     parser_read_file(paramFileName, params);
+
+    /* Handle any command-line overrides. */
+    if (nparams > 0)
+      for (int k = 0; k < nparams; k++)
+        parser_set_param(params, cmdparams[k]);
+
+    /* And dump the parameters as used. */
     // parser_print_params(&params);
     parser_write_params_to_file(params, "used_parameters.yml");
   }
diff --git a/src/parser.c b/src/parser.c
index 41a3e86376..0ff388d439 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1,6 +1,7 @@
 /*******************************************************************************
  * This file is part of SWIFT.
  * Copyright (c) 2016 James Willis (james.s.willis@durham.ac.uk)
+ *               2017 Peter W. Draper (p.w.draper@durham.ac.uk)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published
@@ -89,6 +90,60 @@ void parser_read_file(const char *file_name, struct swift_params *params) {
   fclose(file);
 }
 
+/**
+ * @brief Set or update a parameter using a compressed format.
+ *
+ * The compressed format allows a value to be given as a single
+ * string and has the format "section:parameter:value", with all
+ * names as would be given in the parameter file.
+ *
+ * @param params Structure that holds the parameters.
+ * @param namevalue the parameter name and value as described.
+ */
+void parser_set_param(struct swift_params *params, const char *namevalue) {
+
+  /* Get the various parts. */
+  char name[PARSER_MAX_LINE_SIZE];
+  char value[PARSER_MAX_LINE_SIZE];
+  name[0] = '\0';
+  value[0] = '\0';
+
+  /* Name is part until second colon. */
+  char *p1 = strchr(namevalue, ':');
+  if (p1 != NULL) {
+    char *p2 = strchr(p1+1, ':');
+    if (p2 != NULL) {
+      memcpy(name, namevalue, p2-namevalue);
+      name[p2-namevalue] = '\0';
+
+      /* Value is rest after second colon. */
+      p2++;
+      strcpy(value, p2);
+    }
+  }
+
+  /* Sanity check. */
+  if (strlen(name) == 0 || strlen(value) == 0 || strchr(value, ':') != NULL)
+    error("Cannot parse compressed parameter string: '%s', check syntax "
+          "should be section:parameter:value", namevalue);
+
+  /* And update or set. */
+  int updated = 0;
+  for (int i = 0; i < params->paramCount; i++) {
+    if (strcmp(name, params->data[i].name) == 0) {
+      strcpy(params->data[i].value, value);
+      updated = 1;
+    }
+  }
+  if (!updated) {
+    strcpy(params->data[params->paramCount].name, name);
+    strcpy(params->data[params->paramCount].value, value);
+    params->paramCount++;
+    if (params->paramCount == PARSER_MAX_NO_OF_PARAMS)
+      error("Too many parameters, current maximum is %d.", params->paramCount);
+  }
+}
+
 /**
  * @brief Counts the number of times a specific character appears in a string.
  *
@@ -238,7 +293,7 @@ static void parse_value(char *line, struct swift_params *params) {
 
   /* Check for more than one value on the same line. */
   if (count_char(line, PARSER_VALUE_CHAR) > 1) {
-    error("Inavlid line:%d '%s', only one value allowed per line.", lineNumber,
+    error("Invalid line:%d '%s', only one value allowed per line.", lineNumber,
           line);
   }
 
@@ -718,6 +773,7 @@ void parser_write_params_to_file(const struct swift_params *params,
   fclose(file);
 }
 
+
 #if defined(HAVE_HDF5)
 void parser_write_params_to_hdf5(const struct swift_params *params, hid_t grp) {
 
diff --git a/src/parser.h b/src/parser.h
index b78e21194d..bab6d8b25f 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -1,6 +1,7 @@
 /*******************************************************************************
  * This file is part of SWIFT.
  * Copyright (c) 2016 James Willis (james.s.willis@durham.ac.uk)
+ *               2017 Peter W. Draper (p.w.draper@durham.ac.uk)
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published
@@ -55,6 +56,7 @@ void parser_read_file(const char *file_name, struct swift_params *params);
 void parser_print_params(const struct swift_params *params);
 void parser_write_params_to_file(const struct swift_params *params,
                                  const char *file_name);
+void parser_set_param(struct swift_params *params, const char *desc);
 
 char parser_get_param_char(const struct swift_params *params, const char *name);
 int parser_get_param_int(const struct swift_params *params, const char *name);
-- 
GitLab