schrodinger.application.desmond.multisim.parser module¶
Functions to parse MSJ files
Copyright Schrodinger, LLC. All rights reserved.
- class schrodinger.application.desmond.multisim.parser.Msj(*args, **kwargs)¶
Bases:
schrodinger.application.desmond.arkdb.ArkDb
The use of this class is very similar to
arkdb.ArkDb
. Some terminologies and syntax defined inarkdb.ArkDb
are not repeated here. So if you are unfamiliar witharkdb.ArkDb
, you are encouraged to read the docstrings there. Below are examples to demonstrate and explain the use of this class:msj = parse(msj_fname)
# 1. To read the
time
setting in stage 3: msj.get(“stage[2].simulate.time”) msj.get(“stage[-1].simulate.time”) # -stage[2]
in the key corresponds to stage 3 because the stage index in # the code is always zero based. # - Negative stage indices are supported and are of the same meaning as in # Python. # - The stage type (here it issimulate
) is always needed in the key. This # is good for preventing some kind of index errors, and is very useful # when you do NOT care about the index (see below).# 2. To read the
time
setting in the firstlambda_hopping
stage: msj.get(“stage[i].lambda_hopping.time”)# 3. Default value for non-existing setting: msj.get(“stage[i].lambda_hopping.phony_setting”, 1000)
# 4. To change the value of a setting: msj.put(“stage[i].lambda_hopping.time”, 1000)
# 5. To append a new stage
fep_analysis
and use the stage’s default # settings: msj.put(“stage[$].fep_analysis”, {})# 6. To insert a new stage
build_geometry
to be the 2nd stage: msj.put(“stage[@]1.build_geometry”, {})# 7. To insert a new stage
assign_forcefield
with custom settings:msj.put("stage[@]2.assign_forcefield", sea.Map(``` hydrogen_mass_repartition = off make_alchemical_water = on```))
# Note that it’s necessary to convert the settings in the form of a string # into a
sea.Map
.# 8. To delete the first “simulate” stage: msj.delete(“stage[i].simulate”)
# 9. To delete the “simulate” stage whose title reads “production”: msj.delete(“stage[i].simulate”, matches=”title=production”)
# 10. To delete all “simulate” stages: msj.delete(“stage[*].simulate”)
# 11. To access a particular stage, use the syntax: #
msj.stage[
: msj.stage[10].simulate.time.val += 1000# 12. Support for shorthand keys: msj.put(“lambda_hopping.phony_setting”, 2000) msj.get(“lambda_hopping.phony_setting”) msj.put(“[@]1.build_geometry”, {}) # - If the key starts with the stage type name, it will be assumed to be # prefixed with ‘stage[i].’. In other words, the first instance of the # stage type will be operated on. # - The key can start with ‘[i]’, ‘[*]’, ‘[@]’, and ‘[$]’, and it will be # automatically prefixed with ‘stage’.
# 13. Find the index of the first “simulate” stage: first_simulate_index = msj.find_stages(“[*].simulate”)[0].STAGE_INDEX or simply: first_simulate_index = msj.find_stages(“simulate”)[0].STAGE_INDEX # -
find_stages("simulate")
only returns the first “simulate” stage showing # up in the MSJ file. # - usefind_stages("[*].simulate")
to returns a tuple of all “simulate” stages # found in the MSJ string. # -STAGE_INDEX
gives the stage’s index in the MSJ file. Note that the # index is one-based.# 13. Find the index of the last “trim” stage: last_trim_index = msj.find_stages(“[*].trim”)[-1].STAGE_INDEX # - Here we use the key “[*].trim” to find all “trim” stages and then select # the last one with
[-1]
. # - We don’t use the key “trim” (remember it’s a short hand of “[i].trim”), # because it means to get the first “trim” from the beginning of the stage # list.# 14. Find the index of the second “simulate” stage: second_simulate_index = msj.find_stages(“[*].simulate”)[1].STAGE_INDEX
# 15. Find the index of the “simulate” stage whose “title” parameter is set # to “production”.:
production_index = msj.find_stages("[*].simulate.title" picker=lambda title: (title.parent() if title.val == "production" else None) )[0].STAGE_INDEX
# - With the key “[*].simulate.title”, we find the titles of all simulate # stages, then we use a lambda function as the
picker
to select the # stage whose title is “production”. Note that the “parent” of the “title” # parameter is the stage, which is whattitle.parent()
gives.(Feel free to add more examples)
- __init__(*args, **kwargs)¶
- property stage¶
- get(key: str, *args, **kwargs)¶
Gets a value keyed by
key
. Note thatNone
is a normal return value and does NOT mean that the key was not found.- Raises
CompositeKeySyntaxError – if
key
has a syntax error. You normally should NOT catch this exception, because this means your code has a syntactical error.ArkDbGetError – if
key
is not found in the database. You can optionally change raising the exception to returning a default value by specifying the “default” argument.
Explanation on the value of a
key
:The value is generally a composite key like “a.b.c[1].d”, where “a”, “b”, “c”, “[1]”, and “d” are the subkeys or array-indices at each hierarchical level.
For array indices, sometimes the exact number is unknown a priori, e.g., “ResultLambda0.Keywords[<number>].ProtLigInter”, where the <number> cannot be specified in the source code. For cases like this, we have to iterate over the “ResultLambda0.Keywords” list and find “ProtLigInter” by matching the keyword. Note that it’s possible (at least in principle) that there may be multiple matching elements.
In order to express the above indexing ideas, we introduce four new syntax components here:
- [i] Iterates over elements in the list and returns the first
matching element. For getting, putting, finding, and deleting.
- [*] Iterates over elements in the list and returns a tuple of all
matching elements. Only for getting, finding, and deleting.
[$] Insert at the end of the list. Only for putting.
- [@] Similar to
[$]
except that this is for insertion into an arbitrary position in the list. This is to be used with a number immediately followed, e.g.,
[@]123
, and the number specifies the position in the list. Only for putting.
- [@] Similar to
We may call these meta-indices.
Examples:
“ResultLambda0.Keywords[i].ProtLigInter”: Gets the first “ProtLigInter” data.
“ResultLambda0.Keywords[*].ProtLigInter”: Gets all “ProtLigInter” data, and returns a tuple.
“ResultLambda0.Keywords[@]0.ProtLigInter”: Inserts a new “ProtLigInter” data at “ResultLambda0.Keywords[0]”. Note the difference from using “ResultLambda0.Keywords[0]”, which is to change the existing data.
“ResultLambda0.Keywords[$].ProtLigInter”: Appends a new “ProtLigInter” data to “ResultLambda0.Keywords”.
- put(key: str, *args, **kwargs)¶
Puts a value associated with the given key into this database.
value
can be either of a scalar type, or oflist
, or an emptydict
({}
), or ofsea.Sea
.key
can be a composite key, see the docstring ofArkDb.get
for detail.- Raises
CompositeKeySyntaxError – if
key
has a syntax error. You normally should NOT catch this exception, because this means your code has a syntactical error.ArkDbPutError – if putting failed.
- delete(key: str, *args, **kwargs)¶
Deletes a given
key
and the value from the database. If thekey
is not found,ArkDbDelError
will be raised unlessignore_badkey
isTrue
.matches
, if specified, provides one or more key-value pairs for checking on the value. If and only if all key-value pairs are found in the value, the key and the value will be deleted from the database. Each key-value pair is a string in the format of “<key>=<value>”. Note that the key and the value are connected by a single “=” symbol, no spaces allowed in the connection. Key is in the extended standard composite format (see the docstring of theArkDb
class above). Value is in the ARK format (note that spaces are allowed in the value). The value part is optional, when it’s missing, the “=” symbol should be absent as well, and this function will only look for the key indb
and disregard the value.Examples:
db.delete("a.b.c") db.delete("a.b.d[i].e") db.delete("a.b.d[i]", matches="e") db.delete("a.b.d[i]", matches=("e=5", "h=10"))
- find(key: str, *args, **kwargs)¶
Finds the given
key
and returns the corresponding data as aForEachDo
object. TheForEachDo
object allows to iterate over the found data, each as a newArkDb
(or its subclass) object. It also allows us to concatenate operations on the found data.Example:
db.find("stage[*].simulate").put("ensemble", "NVT") # Resets all simulate stages' "ensemble" parameter's value to "NVT".
If the key is not found, this method will return
()
(i.e., empty tuple).- Parameters
picker –
This is to cherry-pick the found data. The follow types or values are supported:
None: All found data will be returned.
int: Among the found data, a single datum as indexed by
picker
will be returned. The index is zero-based.List[int]: Among the found data, multiple data as indexed by
picker
elements will be returned. The indices are zero-based.Callable:
picker
will be called on each found data, and the results will befilter
-ed and returned.
Example:
db.find("stage[*].task", picker=1) .put("set_family.simulate.temperature", 300) # Mutates the second "task" stage. db.find("stage[*].simulate.restrain", picker=lambda x: x.parent()) .put("temperature", 400) # For any simulate stages with "restrain" setting, resets temperature # to 400.
- find_stages(key: str, *args, **kwargs) Tuple[schrodinger.utils.sea.sea.Map] ¶
Similar to
find
, but to return a tuple of found stages. If no stages are found, this function returns an empty tuple. Examples:# To get all simulate stages: simulate_stages = msj.find_stages("[*].simulate") for stage in simulate_stages: print(stage.STAGE_INDEX) # To get the first simulate stage: first_simulate_stage = msj.find_stages("[*].simulate")[0] print(first_simulate_stage.STAGE_INDEX) # To get the first simulate stage with "time = 200":: simulate = msj.find_stages( "[*].simulate.time", picker= lambda x: (x.parent() if x.val == 200 else None))[0] print(simulate.STAGE_INDEX)
STAGE_INDEX
gives the index of the stage in the MSJ file. Note that the index is one based. Also,STAGE_INDEX
is an attribute (as opposed to a key-value pair) of the returnedsea.Map
objects.
- property val¶
- write(fname: str)¶
- schrodinger.application.desmond.multisim.parser.parse(fname=None, string=None) schrodinger.application.desmond.multisim.parser.Msj ¶
Parses a file or a string, and returns an
Msj
object. Eitherfname
orstring
must be set, but not both.