From e364b80724ae4258e0f3eedbf49236a69fbf0c25 Mon Sep 17 00:00:00 2001
From: Steve Plimpton <sjplimp@sandia.gov>
Date: Fri, 16 Dec 2016 10:24:25 -0700
Subject: [PATCH] added length keyword to python command

---
 doc/src/python.txt           | 15 ++++++++++++++-
 src/PYTHON/python.cpp        | 28 +++++++++++++++++++++++++++-
 src/PYTHON/python.h          |  5 ++++-
 src/USER-INTEL/fix_intel.cpp |  2 --
 src/fix_shear_history.cpp    |  2 +-
 src/variable.cpp             |  4 ++++
 6 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/doc/src/python.txt b/doc/src/python.txt
index 773992bddd..7da69a0319 100644
--- a/doc/src/python.txt
+++ b/doc/src/python.txt
@@ -14,7 +14,7 @@ python func keyword args ... :pre
 
 func = name of Python function :ulb,l
 one or more keyword/args pairs must be appended :l
-keyword = {invoke} or {input} or {return} or {format} or {file} or {here} or {exists}
+keyword = {invoke} or {input} or {return} or {format} or {length} or {file} or {here} or {exists}
   {invoke} arg = none = invoke the previously defined Python function
   {input} args = N i1 i2 ... iN
     N = # of inputs to function
@@ -29,6 +29,8 @@ keyword = {invoke} or {input} or {return} or {format} or {file} or {here} or {ex
     M = N+1 if there is a return value
     fstring = each character (i,f,s,p) corresponds in order to an input or return value
     'i' = integer, 'f' = floating point, 's' = string, 'p' = SELF
+  {length} arg = Nlen
+    Nlen = max length of string returned from Python function
   {file} arg = filename
     filename = file of Python code, which defines func
   {here} arg = inline
@@ -165,6 +167,17 @@ equal-style variable as an argument, but only if the output of the
 Python function is flagged as a numeric value ("i" or "f") via the
 {format} keyword.
 
+If the {return} keyword is used and the {format} keyword specifies the
+output as a string, then the default maximum length of that string is
+63 characters (64-1 for the string terminator).  If you want to return
+a longer string, the {length} keyword can be specified with its {Nlen}
+value set to a larger number (the code allocates space for Nlen+1 to
+include the string terminator).  If the Python function generates a
+string longer than the default 63 or the specified {Nlen}, it will be
+trunctated.
+
+:line
+
 Either the {file}, {here}, or {exists} keyword must be used, but only
 one of them.  These keywords specify what Python code to load into the
 Python interpreter.  The {file} keyword gives the name of a file,
diff --git a/src/PYTHON/python.cpp b/src/PYTHON/python.cpp
index c9947f3521..6c89be6922 100644
--- a/src/PYTHON/python.cpp
+++ b/src/PYTHON/python.cpp
@@ -89,6 +89,7 @@ void Python::command(int narg, char **arg)
   istr = NULL;
   ostr = NULL;
   format = NULL;
+  length_longstr = 0;
   char *pyfile = NULL;
   char *herestr = NULL;
   int existflag = 0;
@@ -115,6 +116,11 @@ void Python::command(int narg, char **arg)
       format = new char[n];
       strcpy(format,arg[iarg+1]);
       iarg += 2;
+    } else if (strcmp(arg[iarg],"length") == 0) {
+      if (iarg+2 > narg) error->all(FLERR,"Invalid python command");
+      length_longstr = force->inumeric(FLERR,arg[iarg+1]);
+      if (length_longstr <= 0) error->all(FLERR,"Invalid python command");
+      iarg += 2;
     } else if (strcmp(arg[iarg],"file") == 0) {
       if (iarg+2 > narg) error->all(FLERR,"Invalid python command");
       delete[] pyfile;
@@ -249,6 +255,7 @@ void Python::invoke_function(int ifunc, char *result)
 
   // function returned a value
   // assign it to result string stored by python-style variable
+  // or if user specified a length, assign it to longstr
 
   if (pfuncs[ifunc].noutput) {
     int otype = pfuncs[ifunc].otype;
@@ -258,7 +265,9 @@ void Python::invoke_function(int ifunc, char *result)
       sprintf(result,"%.15g",PyFloat_AsDouble(pValue));
     } else if (otype == STRING) {
       char *pystr = PyString_AsString(pValue);
-      strncpy(result,pystr,VALUELENGTH-1);
+      if (pfuncs[ifunc].longstr) 
+        strncpy(pfuncs[ifunc].longstr,pystr,pfuncs[ifunc].length_longstr);
+      else strncpy(result,pystr,VALUELENGTH-1);
     }
     Py_DECREF(pValue);
   }
@@ -287,6 +296,13 @@ int Python::variable_match(char *name, char *varname, int numeric)
 
 /* ------------------------------------------------------------------ */
 
+char *Python::long_string(int ifunc)
+{
+  return pfuncs[ifunc].longstr;
+}
+
+/* ------------------------------------------------------------------ */
+
 int Python::create_entry(char *name)
 {
   // ifunc = index to entry by name in pfuncs vector, can be old or new
@@ -370,6 +386,7 @@ int Python::create_entry(char *name)
   // process output as value or variable
 
   pfuncs[ifunc].ovarname = NULL;
+  pfuncs[ifunc].longstr = NULL;
   if (!noutput) return ifunc;
 
   char type = format[ninput];
@@ -378,6 +395,14 @@ int Python::create_entry(char *name)
   else if (type == 's') pfuncs[ifunc].otype = STRING;
   else error->all(FLERR,"Invalid python command");
 
+  if (length_longstr) {
+    if (pfuncs[ifunc].otype != STRING) 
+      error->all(FLERR,"Python command length keyword "
+                 "cannot be used unless output is a string");
+    pfuncs[ifunc].length_longstr = length_longstr;
+    pfuncs[ifunc].longstr = new char[length_longstr+1];
+  }
+
   if (strstr(ostr,"v_") != ostr) error->all(FLERR,"Invalid python command");
   int n = strlen(&ostr[2]) + 1;
   pfuncs[ifunc].ovarname = new char[n];
@@ -398,4 +423,5 @@ void Python::deallocate(int i)
     delete [] pfuncs[i].svalue[j];
   delete [] pfuncs[i].svalue;
   delete [] pfuncs[i].ovarname;
+  delete [] pfuncs[i].longstr;
 }
diff --git a/src/PYTHON/python.h b/src/PYTHON/python.h
index d1622728ac..61e5f015e2 100644
--- a/src/PYTHON/python.h
+++ b/src/PYTHON/python.h
@@ -28,9 +28,10 @@ class Python : protected Pointers {
   void invoke_function(int, char *);
   int find(char *);
   int variable_match(char *, char *, int);
+  char *long_string(int);
 
  private:
-  int ninput,noutput;
+  int ninput,noutput,length_longstr;
   char **istr;
   char *ostr,*format;
   void *pyMain;
@@ -44,6 +45,8 @@ class Python : protected Pointers {
     char **svalue;
     int otype;
     char *ovarname;
+    char *longstr;
+    int length_longstr;
     void *pFunc;
   };
 
diff --git a/src/USER-INTEL/fix_intel.cpp b/src/USER-INTEL/fix_intel.cpp
index 84f4994901..7c5dd0b34c 100644
--- a/src/USER-INTEL/fix_intel.cpp
+++ b/src/USER-INTEL/fix_intel.cpp
@@ -325,8 +325,6 @@ void FixIntel::init()
     error->all(FLERR,
 	       "Currently, cannot use more than one intel style with hybrid.");
 
-  neighbor->fix_intel = (void *)this;
-
   check_neighbor_intel();
   if (_precision_mode == PREC_MODE_SINGLE)
     _single_buffers->zero_ev();
diff --git a/src/fix_shear_history.cpp b/src/fix_shear_history.cpp
index 42d088875b..379de9bcd3 100644
--- a/src/fix_shear_history.cpp
+++ b/src/fix_shear_history.cpp
@@ -526,7 +526,7 @@ double FixShearHistory::memory_usage()
 {
   int nmax = atom->nmax;
   double bytes = nmax * sizeof(int);
-  bytes += nmax * sizeof(int *);
+  bytes += nmax * sizeof(tagint *);
   bytes += nmax * sizeof(double *);
 
   int nmypage = comm->nthreads;
diff --git a/src/variable.cpp b/src/variable.cpp
index 2f985a7c8e..67c8951974 100644
--- a/src/variable.cpp
+++ b/src/variable.cpp
@@ -875,6 +875,10 @@ char *Variable::retrieve(char *name)
       error->all(FLERR,"Python variable does not match Python function");
     python->invoke_function(ifunc,data[ivar][1]);
     str = data[ivar][1];
+    // if Python func returns a string longer than VALUELENGTH
+    // then the Python class stores the result, query it via long_string()
+    char *strlong = python->long_string(ifunc);
+    if (strlong) str = strlong;
   } else if (style[ivar] == INTERNAL) {
     sprintf(data[ivar][0],"%.15g",dvalue[ivar]);
     str = data[ivar][0];
-- 
GitLab