# Using a Model in a Simulation¶

Use your model like this:

```
import hoomd, hoomd.md
import hoomd.htf as htf
...hoomd initialization code...
model = MyModel(32)
tfcompute = htf.tfcompute(model)
nlist = hoomd.md.nlist.cell()
tfcompute.attach(nlist, r_cut=3)
...other hoomd code...
hoomd.run(...)
```

where `MyModel`

is model you created following the steps in Building a Model,
`nlist`

is a hoomd neighbor list object and `r_cut`

is the
maximum distance to consider particles as being neighbors. `nlist`

is optional and is not required if your graph doesn’t use the `nlist`

object (you passed `0`

as the first arg when building your graph).

## Logging¶

The default logging level of TensorFlow is relatively noisy. You can reduce the amount of logged statements via

```
import tensorflow as tf
tf.get_logger().setLevel('ERROR')
```

## Batching¶

If you do not use molecule batching when building your model (i.e., your model isn’t a sub class of :py:class: .MolSimModel, you can
optionally split your batches to be smaller than the entire system. This
is set via the `batch_size`

integer argument to `tfcompute.attach()`

.
This can help for high-memory simulations where you cannot spare the GPU memory to
have each tensor be the size of your system.

## Training¶

Training can be done while running your simulation where the labels are the HOOMD-blue forces. To do this, you must first compile your model as described in Keras documentation. For example,

```
model.compile('Adam', 'mean_squared_error')
```

will compile your model to use mean squared error on per-particle
forces (note that the forces tensor contains energy in the last column) as the loss
and the Adam optimizer. To train while running, just add the `train = True`

arg.

```
tfcompute.attach(train=True)
```

You can also train less than each step (recommended):

```
tfcompute.attach(train=True, period=100)
```

## Model Output¶

By default, your model output is not saved except
to send the forces (and possibly virial) to HOOMD-blue.
You can have `tfcompute`

capture your model output
by adding `save_output_period=100`

. In this case,
output will be saved every 100 steps. Note that
if your model is outputting forces as specified in the
constructor of a `SimModel`

, the forces will not be saved.
Here is a complete example:

```
class MyModel(htf.SimModel):
def compute(self, nlist):
rinv = htf.nlist_rinv(nlist)
energy = rinv
forces = htf.compute_nlist_forces(nlist, energy)
avg_coord_number = tf.reduce_mean(tf.cast(rinv > 0, tf.float32))
return forces, energy, avg_coord_number
model = MyModel(16)
tfcompute = htf.tfcompute(model)
...
...
tfcompute.attach(nlist, rcut=5.0, save_output_period=100)
hoomd.run(1000)
output_energy = tfcompute.outputs[0]
output_avg_coord_number = tfcompute.outputs[1]
```

## Changing Model Object¶

If your `SimModel.compute(nlist, positions, box)`

method depends on attributes of `self`

,
you have to call an `SimModel.retrace_compute()`

if you updated these attributes.
See an example

```
class MyModel(htf.SimModel):
def setup(self, s):
self.s = s
def compute(self, nlist):
rinv = htf.nlist_rinv(nlist)
energy = self.s * rinv
forces = htf.compute_nlist_forces(nlist, energy)
avg_coord_number = tf.reduce_mean(tf.cast(rinv > 0, tf.float32))
return forces, energy, avg_coord_number
model = MyModel(16)
tfcompute = htf.tfcompute(model)
...
...
tfcompute.attach(nlist, rcut=5.0, save_output_period=100)
hoomd.run(1000)
# Now I update s
model.s = 2.5
# I must call retrace_compute
model.retrace_compute()
homod.run(1000)
```