demonstrates the use of a restraint between a real atom and a pseudo atom. This input file should work with Modeller 10.0 or later. You will also need the pseudo.atm input.

from modeller import *
from modeller.optimizers import ConjugateGradients

e = Environ()
e.edat.dynamic_sphere = False

# Read in a dummy PDB, which defines five real atoms - four are positioned at
# the corners of a square in the xy place, and the fifth is off in space
m = Model(e, file='pseudo.atm')

# Define a pseudo atom as the gravity center of the first 4 atoms, and add
# it to the model's restraints
p = pseudo_atom.GravityCenter(m.atoms[0:5])

# Create a restraint on the distance between the real fifth atom and the newly
# created pseudo atom, and add it to the model's restraints. Since the mean is
# zero, this will force atom 5 to coexist with the gravity center.
r = forms.Gaussian(group=physical.xy_distance,
                   feature=features.Distance(m.atoms[4], p),
                   mean=0.0, stdev=0.100)

# Calculate the starting energy of all atoms in the system, then optimize
s = Selection(m)
cg = ConjugateGradients()
cg.optimize(s, max_iterations=200)

# Write out the final coordinates

It is straightforward to add restraints of this type to a comparative modeling run - see for example, Adding additional restraints to the defaults.