'-p': topology_file }, output={'-o': gmx.File(suffix='.tpr')}) # Note: Before gmx.File, users still have to manage filenames # The above would have `output={'-o': [initial_tpr for _ in range(N)]}` # Note: initial_tpr has a single output that can be automatically broadcast now or later. # Broadcast to the read_tpr operation: #simulation_input = gmx.read_tpr([initial_tpr for _ in range(N)]) # Wait to broadcast until the next operation: simulation_input = gmx.read_tpr(initial_tpr.output.file['-o']) # Array inputs imply array outputs. input_array = gmx.modify_input(simulation_input, params={'tau-t': [t / 10.0 for t in range(N)]}) md = gmx.mdrun(input_array) # An array of simulations rmsf = gmx.commandline_operation('gmx', 'rmsf', input={ '-f': md.output.trajectory, '-s': initial_tpr }, output={'-o': gmx.File(suffix='.xvg')}) output_files = gmx.gather(rmsf.output.file['-o']) gmx.run() print('Output file list:') print(', '.join(output_files.result()))
# For subgraphs, inputs can be accessed as variables and are copied to the next # iteration (not typical for gmxapi operation input/output). train = gmx.subgraph(variables={'conformation': initial_input}) # References to the results of operations know which (sub)graph they live in. # The `with` block activates and deactivates the scope of the subgraph in order # to constrain the section of this script in which references are valid. # Otherwise, a user could mistakenly use a reference that only points to the # result of the first iteration of a "while" loop. If the `with` block succeeds, # then the outputs of `train` are afterwards fully specified. with train: myplugin.training_restraint(label='training_potential', params=my_dict_params) modified_input = gmx.modify_input(input=initial_input, structure=train.conformation) md = gmx.mdrun(input=modified_input, potential=train.training_potential) # Alternate syntax to facilitate adding multiple potentials: # md.interface.potential.add(train.training_potential) brer_tools.training_analyzer(label='is_converged', params=train.training_potential.output.alpha) train.conformation = md.output.conformation # At the end of the `with` block, `train` is no longer the active graph, and # gmx.exceptions.ScopeError will be raised if `modified_input`, or `md` are used # in other graph scopes (without first reassigning, of course) # More discussion at https://github.com/kassonlab/gmxapi/issues/205 # In the default work graph, add a node that depends on `condition` and # wraps subgraph. train_loop = gmx.while_loop(operation=train, condition=gmx.logical_not(train.is_converged))
'pair_distance2': gmx.NDArray(0., shape=restraint2_params['nbins']), }) with converge: # ensemble_restraint is implemented using gmxapi ensemble allReduce operations # that do not need to be expressed in this procedural interface. potential1 = myplugin.ensemble_restraint( label='ensemble_restraint_1', params=restraint1_params, input={'pair_distance': converge.pair_distance1}) potential2 = myplugin.ensemble_restraint( label='ensemble_restraint_2', params=restraint2_params, input={'pair_distance': converge.pair_distance2}) md = gmx.mdrun(initial_input) md.interface.potential.add(potential1) md.interface.potential.add(potential2) # Compare the distribution from the current iteration to the experimental # data and look for a threshold of low J-S divergence # We perform the calculation using all of the ensemble data. js_1 = calculate_js( input={ 'params': restraint1_params, 'simulation_distances': gmx.gather(potential1.output.pair_distance) }) js_2 = calculate_js( input={ 'params': restraint2_params, 'simulation_distances': gmx.gather(potential2.output.pair_distance)