An electric field term implemented in pure Python — MMTK User Guide 2.7.7 documentation

### Navigation

- index
- modules |
- MMTK User Guide 2.7.7 documentation »

# An electric field term implemented in pure Python

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    # Electric field term representing a uniform external electric field.
    # It can be added to any other force field.

    from MMTK import ParticleScalar, ParticleVector, SymmetricPairTensor
    from MMTK.ForceFields.ForceField import ForceField, EnergyTerm

    #
    # Each force field term requires two classes. One represents the
    # abstract force field (ElectricField in this example), it knows
    # nothing about any molecular system to which it might be applied.
    # The other one (ElectricFieldTerm) stores all the parameters required
    # for energy evaluation, and provides the actual code.
    #
    # When a force field is evaluated for the first time for a given universe,
    # the method evaluatorTerms() of the force field is called. It creates
    # the EnergyTerm objects. The method evaluate() of the energy term object
    # is called for every energy evaluation. Consequently, as much of the
    # computation as possible should be done outside of this method.
    #

    class ElectricFieldTerm(EnergyTerm):

        # The __init__ method only remembers parameters. Note that
        # EnergyTerm.__init__ takes care of storing the name and the
        # universe object.
        def __init__(self, universe, strength, charges):
            EnergyTerm.__init__(self, 'electric field', universe)
            self.strength = strength
            self.charges = charges

        # This method is called for every single energy evaluation, so make
        # it as efficient as possible. The parameters do_gradients and
        # do_force_constants are flags that indicate if gradients and/or
        # force constants are requested.
        def evaluate(self, configuration, do_gradients, do_force_constants):
            results = {}
            energy = (self.charges*(configuration*self.strength)) \
                     .sumOverParticles()
            results['energy'] = energy
            results['virial'] = -energy
            if do_gradients:
                gradients = ParticleVector(self.universe)
                for atom in self.universe.atomList():
                    gradients[atom] = self.charges[atom]*self.strength
                results['gradients'] = gradients
            if do_force_constants:
                # The force constants are zero -> nothing to calculate.
                results['force_constants'] = SymmetricPairTensor(self.universe)
            else:
                force_constants = None
            return results

    class ElectricField(ForceField):

        """
        Uniform electric field
        """

        def __init__(self, strength, charge_property='amber_charge'):
            """
            @param strength: the electric field vector
            @type strength: L{Scientific.Geometry.Vector}
            @charge_property: the name of the atomic property in the database
                              that is used to retrieve the atomic charges.
                              The default is 'amber_charge', the charge property
                              for Amber94 and Amber99.
            @type charge_property: C{str}
            """
            # Store arguments that recreate the force field from a pickled
            # universe or from a trajectory.
            self.arguments = (strength, charge_property)
            # Initialize the ForceField class, giving a name to this one.
            ForceField.__init__(self, 'electric_field')
            # Store the parameters for later use.
            self.strength = strength
            self.charge_property = charge_property

        # The following method is called by the energy evaluation engine
        # to inquire if this force field term has all the parameters it
        # requires. This is necessary for interdependent force field
        # terms. In our case, we just say "yes" immediately.
        def ready(self, global_data):
            return True

        # The following method is called by the energy evaluation engine
        # to obtain a list of the evaluator objects
        # that handle the calculations.
        def evaluatorTerms(self, universe, subset1, subset2, global_data):
            # The energy for subsets is defined as consisting only
            # of interactions within that subset, so the contribution
            # of an external field is zero. Therefore we just return
            # an empty list of energy terms.
            if subset1 is not None or subset2 is not None:
                return []
            # Collect the charges into an array
            charges = ParticleScalar(universe)
            for o in universe:
                for a in o.atomList():
                    charges[a] = o.getAtomProperty(a, self.charge_property)
            # Here we pass all the parameters to
            # the energy term code that handles energy calculations.
            return [ElectricFieldTerm(universe, self.strength, charges)]

### Navigation

- index
- modules |
- MMTK User Guide 2.7.7 documentation »