Replacing a variable with its value inside a quoted string

Hello all, I’m trying to figure out which commands allow to expand a LAMMPS variable within a triple-quoted multi-line string.

The general rule is that a string “${x}” gets expanded into the value of the variable “x”, except when it is enclosed within quotes. However, the same section also includes an example where the print command is used to print a quoted multi-line string that also includes the expansion of a variable.

It appears that print’s behavior is an exception, as can be seen in the following example, where the python command does not replace “${N}”:

variable N index 101
print """
Value of N = ${N}
"""
python printnum source """
print('Value of N = ${N}')
"""

Is print the only command that behaves differently? If there are others, I would like to understand how these commands are able to expand LAMMPS variables before processing their string arguments.

Thanks!
Giacomo

The important issue here is that the ${name} variable expansion is applied to general input processing, but then the text must not be quoted, but for a few cases, the recorded string is expanded a second time. The print command and fix print are such cases. You can see this because they copy the (quoted) string and then call Input::substitute on it. Here is the corresponding code from the print command: lammps/input.cpp at 4aee151b0e3550ee66a09b038ba5ceaf7e912ead · lammps/lammps · GitHub

There is one more exception to this, and that are the LEPTON package styles, which have their own substitute function and use a different syntax (v_name instead of ${name}): lammps/lepton_utils.cpp at 4aee151b0e3550ee66a09b038ba5ceaf7e912ead · lammps/lammps · GitHub

Thanks, if these are the only exceptions, it doesn’t seem worth it to try and reuse Input::substitute() like fix print does. The chance of me messing up the sizes of the associated buffers when doing so is kinda high :slight_smile:

For the improvements on fix_modify colvars I could just add a dedicated function to process the string arguments similar to the one you have for the Lepton expressions, and just document this exception to the LAMMPS parsing rules. Because the exception would only apply to strings passed to Colvars, it should be fairly clear and obviously there is no existing behavior to break.

Thanks
Giacomo

One of the reasons why I chose to write my own substitution function was similar. The second is that the ${name} expansion on fix print (or print) is actually more similar to the v_name expansion. That inconsistency always bothered me.

@sjplimp recently added variable expansion to the MDI package, so you can learn from that (he invented the input parser, so he should know how to not mess it up). enable variables in MDI commands · lammps/lammps@f9be11a · GitHub

It is also possible to move the substitute function from the LEPTON package to the utils namespace (there is nothing Lepton specific in it, only that it is not used elsewhere so far).

Of course you are also free to copy and modify it as needed for your purposes.

Actually, upon closer look I see that you are using the fmt:: utility functions to replace instances of “{}” with the variable’s values. Unfortunately, that string is legitimate Colvars syntax (although a useless example of it) so I don’t think that your function would work for me as-is, even if you move it to utils.

Need to think more about this. Following Steve’s example (which seems quite similar to fix print) is an option. Or I could just use single-line scripting calls to Colvars to edit individual parameters rather than editing replace an entire config string.

Looks like it was easier than I thought… Input::substitute() takes references to pointers and their sizes, and reallocates them as needed. So I was able to make it work by simply lifting those few lines.

For the record, I agree that v_name is much better for Lepton expressions, where one clearly wants a reference to the variable rather than immediate expansion. In the use case that I was dealing with (embedding parameters in a configuration string), ${name} is the more appropriate choice.

1 Like