Rigid Bottlebrush

This example generates 50 bottlebrush polymers with 10-15 backbone beads with 50% of the beads grafted to a 2-bead long flexible side chain. In order to build this, we can start with the backbone, a standard Kremer-Grest model with added angle potentials along the chain. Note that arbitrary functions can be passed as arguments nearly everywhere in hoobas

>>> backbone = hoobas.LinearChain.GenericPolymer(n_mono=lambda: np.random.randint(10, 15), rigid=True, beadname='A')

The rigid argument creates angles along the chain, while n_mono is polydisperse. When using functions with a random component, remember that every object will be created separately and is unique.

Linear chains are generally defined along the z coordinate, so we will graft chains in the (x,y) plane. Here, let’s define an arbitrary orientation in that plane

def random_xy():
    angle = np.random.uniform(0, 2*math.pi)
    return np.array([math.cos(angle), math.sin(angle), 0.0])

We can now attach grafting sites along this backbone:

>>> backbone.add_free_attachment_sites(key_search={}, properties={'orientation': random_xy})

Since the properties contain a random function, every grafting point will be unique. The sidechain is fairly boring, a simple fixed-length Kremer-Grest chain, with an attachment site pointing downwards on the first bead

>>> sidechain = hoobas.LinearChain.GenericPolymer(n_mono=2, rigid=False, beadname='B')
>>> sidechain.add_free_attachment_sites(key_search={'index': 0}, properties={'orientation': np.array([0., 0., -1.0])})

Grafting on 50% of the chain requires knowing chain length, which is in principle problematic since it is not a fixed number. Fortunately, hoobas.LinearChain.LinearChain defines a quantity named number_monomers, which is computed to be the number of added monomers when the chain is built. We can make any topology modifying function query properties of hoobas.Composite.CompositeObject by using named arguments:

>>> backbone.graft_external_objects(external_object=sidechain,
                                    number=lambda number_monomers: int(number_monomers*0.5),
                                    connecting_topology=hoobas.Composite.BondType('A-B',
                                    topodict={'energy_constant': 1.0, 'distance_constant': 1.0},
                                    unitdict={'energy_constant': 'E/LL','distance_constant': 'L'}))

Hoobas uses hoobas.SimulationDomain.Domain objects to represent the overall environment. Here, we are interested in a regular “isotropic” environment, so we will start with an empty cubic box, of size 30.0

>>> Domain = hoobas.SimulationDomain.EmptyCube(size = 30.0)

Hoobas uses hoobas.Build.Builder objects to assemble simulations. Here, we can initialize it with an empty domain:

>>> builder = hoobas.Builder.HOOMDBuilder(Domain)

And we can then add our bottlebrushes to the current build :

>>> builder.add_N_ext_obj(backbone, 50)