tclvmd

Tcl Unmatched open quote in list. VMD MMPBSA error


I've been trying to run MMPBSA calculations using CAFE, however, when I use -pb_rad charmm. VMD prints the following error when it begins to run PB calculations: "Unmatched open quote in list "

I suspect that the error originates from the following section of the cafe_mmpsa script:

 if { $pb } {
    show -info "Calculating the PB term"
    set start [clock seconds]

    # assign radii
    set ar_args "$currmol $pb_rad"
    if { $pb_rad eq "charmm" } {
        foreach p $parfile { append ar_args " \"$p\"" }
    } elseif { $pb_rad eq "parm7" } {
        append ar_args " \"$topfile\""
    }
    eval assign_radii $ar_args

    set com_pb_list [calc_pb $currmol com $comsel]

    if { $recsel ne "" } {
        set rec_pb_list [calc_pb $currmol rec $recsel]
    }

    if { $ligsel ne "" } {
        set lig_pb_list [calc_pb $currmol lig $ligsel]
    }

    foreach { d h m s } [timer $start] { break }
    show -info "It took $d days $h hrs $m min $s sec"
}

However I need help identifying the part that needs correction. I am hoping someone can help me or recommend any other PB Radius I could use.

Thank you, Javier


Solution

  • You're building a string that is a tcl command, and evaluating it. Part of what you're doing is adding quotes around arguments, which handles things like spaces in the arguments, but if they themselves have quotes, you have to take special action to avoid issues.

    A demonstration of the sort of thing you're likely running into:

    % set demo "list "
    list
    % append demo "\"foo bar\""
    list "foo bar"
    % set x "another \"string\""
    another "string"
    % append demo " \"$x\""
    list "foo bar" "another "string""
    % eval $demo
    extra characters after close-quote
    

    In modern versions of tcl, the easy way to get around that is to build a list of arguments, not a string, and use {*} to expand it:

    set ar_args [list $currmol $pb_rad]
    if { $pb_rad eq "charmm" } {
        lappend ar_args {*}$parfile
    } elseif { $pb_rad eq "parm7" } {
        lappend ar_args $topfile
    }
    assign_radii {*}$ar_args
    

    Some quick googling suggests that this VMD program is still using tcl 8.4.1, which was released in... 2002. Just a little bit outdated.

    Luckily, the Tcler's Wiki page on eval still demonstrates the historical alternative to {*} that builds a list and uses that as the argument to eval, relying on stringification to handle quoting issues:

    % set demo [list list]
    list
    % lappend demo "\"foo bar\""
    list {"foo bar"}
    % lappend demo $x
    list {"foo bar"} {another "string"}
    % eval $demo
    {"foo bar"} {another "string"}
    

    or, adapting to your code:

    set ar_args [list assign_radii $currmol $pb_rad]
    if { $pb_rad eq "charmm" } {
        # foreach p $parfile { lappend ar_args $p }
        eval [linsert $parfile 0 lappend ar_args] ;# Avoid a loop
    } elseif { $pb_rad eq "parm7" } {
        lappend ar_args $topfile
    }
    eval $ar_args