class ForcePartValence(ForcePart): '''The covalent part of a force-field model. The covalent force field is implemented in a three-layer approach, similar to the implementation of a neural network: 1. The first layer consists of a :class:`yaff.pes.dlist.DeltaList` object that computes all the relative vectors needed for the internal coordinates in the covalent energy terms. This list is automatically built up as energy terms are added with the ``add_term`` method. This list also takes care of transforming `derivatives of the energy towards relative vectors` into `derivatives of the energy towards Cartesian coordinates and the virial tensor`. 2. The second layer consist of a :class:`yaff.pes.iclist.InternalCoordinateList` object that computes the internal coordinates, based on the ``DeltaList``. This list is also automatically built up as energy terms are added. The same list is also responsible for transforming `derivatives of the energy towards internal coordinates` into `derivatives of the energy towards relative vectors`. 3. The third layers consists of a :class:`yaff.pes.vlist.ValenceList` object. This list computes the covalent energy terms, based on the result in the ``InternalCoordinateList``. This list also computes the derivatives of the energy terms towards the internal coordinates. The computation of the covalent energy is the so-called `forward code path`, which consists of running through steps 1, 2 and 3, in that order. The derivatives of the energy are computed in the so-called `backward code path`, which consists of taking steps 1, 2 and 3 in reverse order. This basic idea of back-propagation for the computation of derivatives comes from the field of neural networks. More details can be found in the chapter, :ref:`dg_sec_backprop`. ''' def __init__(self, system): ''' **Arguments:** system An instance of the ``System`` class. ''' ForcePart.__init__(self, 'valence', system) self.dlist = DeltaList(system) self.iclist = InternalCoordinateList(self.dlist) self.vlist = ValenceList(self.iclist) if log.do_medium: with log.section('FPINIT'): log('Force part: %s' % self.name) log.hline() def add_term(self, term): '''Add a new term to the covalent force field. **Arguments:** term An instance of the class :class:`yaff.pes.ff.vlist.ValenceTerm`. In principle, one should add all energy terms before calling the ``compute`` method, but with the current implementation of Yaff, energy terms can be added at any time. (This may change in future.) ''' if log.do_high: with log.section('VTERM'): log('%7i&%s %s' % (self.vlist.nv, term.get_log(), ' '.join(ic.get_log() for ic in term.ics))) self.vlist.add_term(term) def _internal_compute(self, gpos, vtens): with timer.section('Valence'): self.dlist.forward() self.iclist.forward() energy = self.vlist.forward() if not ((gpos is None) and (vtens is None)): self.vlist.back() self.iclist.back() self.dlist.back(gpos, vtens) return energy
class ForcePartValence(ForcePart): '''The covalent part of a force-field model. The covalent force field is implemented in a three-layer approach, similar to the implementation of a neural network: (0. Optional, not used by default. A layer that computes centers of mass for groups of atoms.) 1. The first layer consists of a :class:`yaff.pes.dlist.DeltaList` object that computes all the relative vectors needed for the internal coordinates in the covalent energy terms. This list is automatically built up as energy terms are added with the ``add_term`` method. This list also takes care of transforming `derivatives of the energy towards relative vectors` into `derivatives of the energy towards Cartesian coordinates and the virial tensor`. 2. The second layer consist of a :class:`yaff.pes.iclist.InternalCoordinateList` object that computes the internal coordinates, based on the ``DeltaList``. This list is also automatically built up as energy terms are added. The same list is also responsible for transforming `derivatives of the energy towards internal coordinates` into `derivatives of the energy towards relative vectors`. 3. The third layers consists of a :class:`yaff.pes.vlist.ValenceList` object. This list computes the covalent energy terms, based on the result in the ``InternalCoordinateList``. This list also computes the derivatives of the energy terms towards the internal coordinates. The computation of the covalent energy is the so-called `forward code path`, which consists of running through steps 1, 2 and 3, in that order. The derivatives of the energy are computed in the so-called `backward code path`, which consists of taking steps 1, 2 and 3 in reverse order. This basic idea of back-propagation for the computation of derivatives comes from the field of neural networks. More details can be found in the chapter, :ref:`dg_sec_backprop`. ''' def __init__(self, system): ''' Parameters ---------- system An instance of the ``System`` class. ''' ForcePart.__init__(self, 'valence', system) # override self.gpos to the correct size! # natom of COMSystem object will return number of beads # but gpos has to have the size (n_atoms, 3), to be consisten # with the other parts of the force field self.dlist = DeltaList(system) self.iclist = InternalCoordinateList(self.dlist) self.vlist = ValenceList(self.iclist) if log.do_medium: with log.section('FPINIT'): log('Force part: %s' % self.name) log.hline() def add_term(self, term): '''Add a new term to the covalent force field. **Arguments:** term An instance of the class :class:`yaff.pes.ff.vlist.ValenceTerm`. In principle, one should add all energy terms before calling the ``compute`` method, but with the current implementation of Yaff, energy terms can be added at any time. (This may change in future.) ''' if log.do_high: with log.section('VTERM'): log('%7i&%s %s' % (self.vlist.nv, term.get_log(), ' '.join( ic.get_log() for ic in term.ics))) self.vlist.add_term(term) def _internal_compute(self, gpos, vtens): with timer.section('Valence'): self.dlist.forward() self.iclist.forward() energy = self.vlist.forward() if not ((gpos is None) and (vtens is None)): self.vlist.back() self.iclist.back() self.dlist.back(gpos, vtens) return energy