Ejemplo n.º 1
0
    def bind(self, beads, ensemble):
        """ Initializes the normal modes object and binds to beads and ensemble.

      Do all the work down here as we need a full-formed necklace and ensemble
      to know how this should be done.

      Args:
         beads: A beads object to be bound.
         ensemble: An ensemble object to be bound.
      """

        self.nbeads = beads.nbeads
        self.natoms = beads.natoms

        # stores a reference to the bound beads and ensemble objects
        self.beads = beads
        self.ensemble = ensemble

        # sets up what's necessary to perform nm transformation.
        if self.transform_method == "fft":
            self.transform = nmtransform.nm_fft(nbeads=self.nbeads,
                                                natoms=self.natoms)
        elif self.transform_method == "matrix":
            self.transform = nmtransform.nm_trans(nbeads=self.nbeads)

        # creates arrays to store normal modes representation of the path.
        # must do a lot of piping to create "ex post" a synchronization between the beads and the nm
        sync_q = synchronizer()
        sync_p = synchronizer()
        dset(
            self, "qnm",
            depend_array(
                name="qnm",
                value=np.zeros((self.nbeads, 3 * self.natoms), float),
                func={
                    "q": (lambda: self.transform.b2nm(depstrip(self.beads.q)))
                },
                synchro=sync_q))
        dset(
            self, "pnm",
            depend_array(
                name="pnm",
                value=np.zeros((self.nbeads, 3 * self.natoms), float),
                func={
                    "p": (lambda: self.transform.b2nm(depstrip(self.beads.p)))
                },
                synchro=sync_p))

        # must overwrite the functions
        dget(self.beads, "q")._func = {
            "qnm": (lambda: self.transform.nm2b(depstrip(self.qnm)))
        }
        dget(self.beads, "p")._func = {
            "pnm": (lambda: self.transform.nm2b(depstrip(self.pnm)))
        }
        dget(self.beads, "q").add_synchro(sync_q)
        dget(self.beads, "p").add_synchro(sync_p)

        # also within the "atomic" interface to beads
        for b in range(self.nbeads):
            dget(self.beads._blist[b], "q")._func = {
                "qnm": (lambda: self.transform.nm2b(depstrip(self.qnm)))
            }
            dget(self.beads._blist[b], "p")._func = {
                "pnm": (lambda: self.transform.nm2b(depstrip(self.pnm)))
            }
            dget(self.beads._blist[b], "q").add_synchro(sync_q)
            dget(self.beads._blist[b], "p").add_synchro(sync_p)

        # finally, we mark the beads as those containing the set positions
        dget(self.beads, "q").update_man()
        dget(self.beads, "p").update_man()

        # create path-frequencies related properties
        dset(
            self, "omegan",
            depend_value(name='omegan',
                         func=self.get_omegan,
                         dependencies=[dget(self.ensemble, "temp")]))
        dset(
            self, "omegan2",
            depend_value(name='omegan2',
                         func=self.get_omegan2,
                         dependencies=[dget(self, "omegan")]))
        dset(
            self, "omegak",
            depend_array(name='omegak',
                         value=np.zeros(self.beads.nbeads, float),
                         func=self.get_omegak,
                         dependencies=[dget(self, "omegan")]))

        # sets up "dynamical" masses -- mass-scalings to give the correct RPMD/CMD dynamics
        dset(
            self, "nm_factor",
            depend_array(
                name="nmm",
                value=np.zeros(self.nbeads, float),
                func=self.get_nmm,
                dependencies=[dget(self, "nm_freqs"),
                              dget(self, "mode")]))
        dset(
            self, "dynm3",
            depend_array(
                name="dm3",
                value=np.zeros((self.nbeads, 3 * self.natoms), float),
                func=self.get_dynm3,
                dependencies=[dget(self, "nm_factor"),
                              dget(self.beads, "m3")]))
        dset(
            self, "dynomegak",
            depend_array(
                name="dynomegak",
                value=np.zeros(self.nbeads, float),
                func=self.get_dynwk,
                dependencies=[dget(self, "nm_factor"),
                              dget(self, "omegak")]))

        dset(
            self, "prop_pq",
            depend_array(name='prop_pq',
                         value=np.zeros((self.beads.nbeads, 2, 2)),
                         func=self.get_prop_pq,
                         dependencies=[
                             dget(self, "omegak"),
                             dget(self, "nm_factor"),
                             dget(self.ensemble, "dt")
                         ]))

        # if the mass matrix is not the RPMD one, the MD kinetic energy can't be
        # obtained in the bead representation because the masses are all mixed up
        dset(
            self, "kins",
            depend_array(name="kins",
                         value=np.zeros(self.nbeads, float),
                         func=self.get_kins,
                         dependencies=[
                             dget(self, "pnm"),
                             dget(self.beads, "sm3"),
                             dget(self, "nm_factor")
                         ]))
        dset(
            self, "kin",
            depend_value(name="kin",
                         func=self.get_kin,
                         dependencies=[dget(self, "kins")]))
        dset(
            self, "kstress",
            depend_array(name="kstress",
                         value=np.zeros((3, 3), float),
                         func=self.get_kstress,
                         dependencies=[
                             dget(self, "pnm"),
                             dget(self.beads, "sm3"),
                             dget(self, "nm_factor")
                         ]))
Ejemplo n.º 2
0
    def bind(self, ensemble, motion, beads=None, forces=None):
        """ Initializes the normal modes object and binds to beads and ensemble.

        Do all the work down here as we need a full-formed necklace and ensemble
        to know how this should be done.

        Args:
           beads: A beads object to be bound.
           ensemble: An ensemble object to be bound.
        """

        self.ensemble = ensemble
        self.motion = motion
        if beads is None:
            self.beads = motion.beads
        else:
            self.beads = beads
        self.forces = forces
        self.nbeads = beads.nbeads
        self.natoms = beads.natoms

        dself = dd(self)

        # stores a reference to the bound beads and ensemble objects
        self.ensemble = ensemble
        dpipe(dd(motion).dt, dself.dt)

        # sets up what's necessary to perform nm transformation.
        if self.transform_method == "fft":
            self.transform = nmtransform.nm_fft(nbeads=self.nbeads, natoms=self.natoms, open_paths=self.open_paths)
        elif self.transform_method == "matrix":
            self.transform = nmtransform.nm_trans(nbeads=self.nbeads, open_paths=self.open_paths)

        # creates arrays to store normal modes representation of the path.
        # must do a lot of piping to create "ex post" a synchronization between the beads and the nm
        sync_q = synchronizer()
        sync_p = synchronizer()
        dself.qnm = depend_array(name="qnm",
                                 value=np.zeros((self.nbeads, 3 * self.natoms), float),
                                 func={"q": (lambda: self.transform.b2nm(dstrip(self.beads.q)))},
                                 synchro=sync_q)
        dself.pnm = depend_array(name="pnm",
                                 value=np.zeros((self.nbeads, 3 * self.natoms), float),
                                 func={"p": (lambda: self.transform.b2nm(dstrip(self.beads.p)))},
                                 synchro=sync_p)

        # must overwrite the functions
        dd(self.beads).q._func = {"qnm": (lambda: self.transform.nm2b(dstrip(self.qnm)))}
        dd(self.beads).p._func = {"pnm": (lambda: self.transform.nm2b(dstrip(self.pnm)))}
        dd(self.beads).q.add_synchro(sync_q)
        dd(self.beads).p.add_synchro(sync_p)

        # also within the "atomic" interface to beads
        for b in range(self.nbeads):
            dd(self.beads._blist[b]).q._func = {"qnm": (lambda: self.transform.nm2b(dstrip(self.qnm)))}
            dd(self.beads._blist[b]).p._func = {"pnm": (lambda: self.transform.nm2b(dstrip(self.pnm)))}
            dd(self.beads._blist[b]).q.add_synchro(sync_q)
            dd(self.beads._blist[b]).p.add_synchro(sync_p)

        # finally, we mark the beads as those containing the set positions
        dd(self.beads).q.update_man()
        dd(self.beads).p.update_man()

        # forces can be converted in nm representation, but here it makes no sense to set up a sync mechanism,
        # as they always get computed in the bead rep
        if not self.forces is None:
            dself.fnm = depend_array(name="fnm",
                                     value=np.zeros((self.nbeads, 3 * self.natoms), float), func=(lambda: self.transform.b2nm(dstrip(self.forces.f))),
                                     dependencies=[dd(self.forces).f])
        else:  # have a fall-back plan when we don't want to initialize a force mechanism, e.g. for ring-polymer initialization
            dself.fnm = depend_array(name="fnm",
                                     value=np.zeros((self.nbeads, 3 * self.natoms), float),
                                     func=(lambda: depraise(ValueError("Cannot access NM forces when initializing the NM object without providing a force reference!"))),
                                     dependencies=[])

        # create path-frequencies related properties
        dself.omegan = depend_value(name='omegan', func=self.get_omegan,
                                    dependencies=[dd(self.ensemble).temp])
        dself.omegan2 = depend_value(name='omegan2', func=self.get_omegan2,
                                     dependencies=[dself.omegan])
        dself.omegak = depend_array(name='omegak',
                                    value=np.zeros(self.beads.nbeads, float),
                                    func=self.get_omegak, dependencies=[dself.omegan])
        dself.omegak2 = depend_array(name='omegak2',
                                    value=np.zeros(self.beads.nbeads, float),
                                    func=(lambda: self.omegak**2), dependencies=[dself.omegak])

        # Add o_omegak to calculate the freq in the case of open path
        dself.o_omegak = depend_array(name='o_omegak',
                                      value=np.zeros(self.beads.nbeads, float),
                                      func=self.get_o_omegak, dependencies=[dself.omegan])

        # sets up "dynamical" masses -- mass-scalings to give the correct RPMD/CMD dynamics
        dself.nm_factor = depend_array(name="nm_factor",
                                       value=np.zeros(self.nbeads, float), func=self.get_nmm,
                                       dependencies=[dself.nm_freqs, dself.mode])
        # add o_nm_factor for the dynamical mass in the case of open paths
        dself.o_nm_factor = depend_array(name="nmm",
                                         value=np.zeros(self.nbeads, float), func=self.get_o_nmm,
                                         dependencies=[dself.nm_freqs, dself.mode])
        dself.dynm3 = depend_array(name="dynm3",
                                   value=np.zeros((self.nbeads, 3 * self.natoms), float), func=self.get_dynm3,
                                   dependencies=[dself.nm_factor, dd(self.beads).m3])
        dself.dynomegak = depend_array(name="dynomegak",
                                       value=np.zeros(self.nbeads, float), func=self.get_dynwk,
                                       dependencies=[dself.nm_factor, dself.omegak])

        dself.dt = depend_value(name="dt", value=1.0)
        dpipe(dd(self.motion).dt, dself.dt)
        dself.prop_pq = depend_array(name='prop_pq', value=np.zeros((self.beads.nbeads, 2, 2)),
                                     func=self.get_prop_pq,
                                     dependencies=[dself.omegak, dself.nm_factor, dself.dt])
        dself.o_prop_pq = depend_array(name='o_prop_pq', value=np.zeros((self.beads.nbeads, 2, 2)),
                                       func=self.get_o_prop_pq,
                                       dependencies=[dself.o_omegak, dself.o_nm_factor, dself.dt])

        # if the mass matrix is not the RPMD one, the MD kinetic energy can't be
        # obtained in the bead representation because the masses are all mixed up
        dself.kins = depend_array(name="kins", value=np.zeros(self.nbeads, float),
                                  func=self.get_kins,
                                  dependencies=[dself.pnm, dd(self.beads).sm3, dself.nm_factor])
        dself.kin = depend_value(name="kin", func=self.get_kin,
                                 dependencies=[dself.kins])
        dself.kstress = depend_array(name="kstress", value=np.zeros((3, 3), float),
                                     func=self.get_kstress,
                                     dependencies=[dself.pnm, dd(self.beads).sm3, dself.nm_factor])

        # spring energy, calculated in normal modes
        dself.vspring = depend_value(name="vspring",
                                     value=0.0, func=self.get_vspring,
                                     dependencies=[dself.qnm, dself.omegak, dd(self.beads).m3])

        # spring forces on normal modes
        dself.fspringnm = depend_array(name="fspringnm",
                                       value=np.zeros((self.nbeads, 3 * self.natoms), float),
                                       func=self.get_fspringnm,
                                       dependencies=[dself.qnm, dself.omegak, dd(self.beads).m3])

        # spring forces on beads, transformed from normal modes
        dself.fspring = depend_array(name="fs",
                                     value=np.zeros((self.nbeads, 3 * self.natoms), float),
                                     func=(lambda: self.transform.nm2b(dstrip(self.fspringnm))),
                                     dependencies=[dself.fspringnm])
Ejemplo n.º 3
0
    def bind(self, ensemble, motion, beads=None, forces=None):
        """ Initializes the normal modes object and binds to beads and ensemble.

        Do all the work down here as we need a full-formed necklace and ensemble
        to know how this should be done.

        Args:
           beads: A beads object to be bound.
           ensemble: An ensemble object to be bound.
        """

        self.ensemble = ensemble
        self.motion = motion
        if beads is None:
            self.beads = motion.beads
        else:
            self.beads = beads
        self.forces = forces
        self.nbeads = beads.nbeads
        self.natoms = beads.natoms

        dself = dd(self)

        # stores a reference to the bound beads and ensemble objects
        self.ensemble = ensemble
        dpipe(dd(motion).dt, dself.dt)

        # sets up what's necessary to perform nm transformation.
        if self.nbeads == 1:  # classical trajectory! don't waste time doing anything!
            self.transform = nmtransform.nm_noop(nbeads = self.nbeads)
        elif self.transform_method == "fft":
            self.transform = nmtransform.nm_fft(nbeads=self.nbeads, natoms=self.natoms, open_paths=self.open_paths)
        elif self.transform_method == "matrix":
            self.transform = nmtransform.nm_trans(nbeads=self.nbeads, open_paths=self.open_paths)

        # creates arrays to store normal modes representation of the path.
        # must do a lot of piping to create "ex post" a synchronization between the beads and the nm
        sync_q = synchronizer()
        sync_p = synchronizer()
        dself.qnm = depend_array(name="qnm",
                                 value=np.zeros((self.nbeads, 3 * self.natoms), float),
                                 func={"q": (lambda: self.transform.b2nm(dstrip(self.beads.q)))},
                                 synchro=sync_q)
        dself.pnm = depend_array(name="pnm",
                                 value=np.zeros((self.nbeads, 3 * self.natoms), float),
                                 func={"p": (lambda: self.transform.b2nm(dstrip(self.beads.p)))},
                                 synchro=sync_p)

        # must overwrite the functions
        dd(self.beads).q._func = {"qnm": (lambda: self.transform.nm2b(dstrip(self.qnm)))}
        dd(self.beads).p._func = {"pnm": (lambda: self.transform.nm2b(dstrip(self.pnm)))}
        dd(self.beads).q.add_synchro(sync_q)
        dd(self.beads).p.add_synchro(sync_p)

        # also within the "atomic" interface to beads
        for b in range(self.nbeads):
            dd(self.beads._blist[b]).q._func = {"qnm": (lambda: self.transform.nm2b(dstrip(self.qnm)))}
            dd(self.beads._blist[b]).p._func = {"pnm": (lambda: self.transform.nm2b(dstrip(self.pnm)))}
            dd(self.beads._blist[b]).q.add_synchro(sync_q)
            dd(self.beads._blist[b]).p.add_synchro(sync_p)

        # finally, we mark the beads as those containing the set positions
        dd(self.beads).q.update_man()
        dd(self.beads).p.update_man()

        # forces can be converted in nm representation, but here it makes no sense to set up a sync mechanism,
        # as they always get computed in the bead rep
        if not self.forces is None:
            dself.fnm = depend_array(name="fnm",
                                     value=np.zeros((self.nbeads, 3 * self.natoms), float), func=(lambda: self.transform.b2nm(dstrip(self.forces.f))),
                                     dependencies=[dd(self.forces).f])
        else:  # have a fall-back plan when we don't want to initialize a force mechanism, e.g. for ring-polymer initialization
            dself.fnm = depend_array(name="fnm",
                                     value=np.zeros((self.nbeads, 3 * self.natoms), float),
                                     func=(lambda: depraise(ValueError("Cannot access NM forces when initializing the NM object without providing a force reference!"))),
                                     dependencies=[])

        # create path-frequencies related properties
        dself.omegan = depend_value(name='omegan', func=self.get_omegan,
                                    dependencies=[dd(self.ensemble).temp])
        dself.omegan2 = depend_value(name='omegan2', func=self.get_omegan2,
                                     dependencies=[dself.omegan])
        dself.omegak = depend_array(name='omegak',
                                    value=np.zeros(self.beads.nbeads, float),
                                    func=self.get_omegak, dependencies=[dself.omegan])
        dself.omegak2 = depend_array(name='omegak2',
                                     value=np.zeros(self.beads.nbeads, float),
                                     func=(lambda: self.omegak**2), dependencies=[dself.omegak])

        # Add o_omegak to calculate the freq in the case of open path
        dself.o_omegak = depend_array(name='o_omegak',
                                      value=np.zeros(self.beads.nbeads, float),
                                      func=self.get_o_omegak, dependencies=[dself.omegan])

        # sets up "dynamical" masses -- mass-scalings to give the correct RPMD/CMD dynamics
        dself.nm_factor = depend_array(name="nm_factor",
                                       value=np.zeros(self.nbeads, float), func=self.get_nmm,
                                       dependencies=[dself.nm_freqs, dself.mode])
        # add o_nm_factor for the dynamical mass in the case of open paths
        dself.o_nm_factor = depend_array(name="nmm",
                                         value=np.zeros(self.nbeads, float), func=self.get_o_nmm,
                                         dependencies=[dself.nm_freqs, dself.mode])
        dself.dynm3 = depend_array(name="dynm3",
                                   value=np.zeros((self.nbeads, 3 * self.natoms), float), func=self.get_dynm3,
                                   dependencies=[dself.nm_factor, dd(self.beads).m3])
        dself.dynomegak = depend_array(name="dynomegak",
                                       value=np.zeros(self.nbeads, float), func=self.get_dynwk,
                                       dependencies=[dself.nm_factor, dself.omegak])

        dself.dt = depend_value(name="dt", value=1.0)
        dpipe(dd(self.motion).dt, dself.dt)
        dself.prop_pq = depend_array(name='prop_pq', value=np.zeros((self.beads.nbeads, 2, 2)),
                                     func=self.get_prop_pq,
                                     dependencies=[dself.omegak, dself.nm_factor, dself.dt])
        dself.o_prop_pq = depend_array(name='o_prop_pq', value=np.zeros((self.beads.nbeads, 2, 2)),
                                       func=self.get_o_prop_pq,
                                       dependencies=[dself.o_omegak, dself.o_nm_factor, dself.dt])

        # if the mass matrix is not the RPMD one, the MD kinetic energy can't be
        # obtained in the bead representation because the masses are all mixed up
        dself.kins = depend_array(name="kins", value=np.zeros(self.nbeads, float),
                                  func=self.get_kins,
                                  dependencies=[dself.pnm, dd(self.beads).sm3, dself.nm_factor])
        dself.kin = depend_value(name="kin", func=self.get_kin,
                                 dependencies=[dself.kins])
        dself.kstress = depend_array(name="kstress", value=np.zeros((3, 3), float),
                                     func=self.get_kstress,
                                     dependencies=[dself.pnm, dd(self.beads).sm3, dself.nm_factor])

        # spring energy, calculated in normal modes
        dself.vspring = depend_value(name="vspring",
                                     value=0.0, func=self.get_vspring,
                                     dependencies=[dself.qnm, dself.omegak, dself.o_omegak, dd(self.beads).m3])

        # spring forces on normal modes
        dself.fspringnm = depend_array(name="fspringnm",
                                       value=np.zeros((self.nbeads, 3 * self.natoms), float),
                                       func=self.get_fspringnm,
                                       dependencies=[dself.qnm, dself.omegak, dd(self.beads).m3])

        # spring forces on beads, transformed from normal modes
        dself.fspring = depend_array(name="fs",
                                     value=np.zeros((self.nbeads, 3 * self.natoms), float),
                                     func=(lambda: self.transform.nm2b(dstrip(self.fspringnm))),
                                     dependencies=[dself.fspringnm])
Ejemplo n.º 4
0
   def bind(self, ensemble, motion, beads=None, forces=None):
      """ Initializes the normal modes object and binds to beads and ensemble.

      Do all the work down here as we need a full-formed necklace and ensemble
      to know how this should be done.

      Args:
         beads: A beads object to be bound.
         ensemble: An ensemble object to be bound.
      """

      self.ensemble = ensemble
      self.motion = motion      
      if beads is None: 
        self.beads = motion.beads
      else:
        self.beads = beads
      self.forces = forces
      self.nbeads = beads.nbeads
      self.natoms = beads.natoms

      # stores a reference to the bound beads and ensemble objects
      self.ensemble = ensemble
      deppipe(motion, "dt", self, "dt")

      # sets up what's necessary to perform nm transformation.
      if self.transform_method == "fft":
         self.transform = nmtransform.nm_fft(nbeads=self.nbeads, natoms=self.natoms)
      elif self.transform_method == "matrix":
         self.transform = nmtransform.nm_trans(nbeads=self.nbeads)

      # creates arrays to store normal modes representation of the path.
      # must do a lot of piping to create "ex post" a synchronization between the beads and the nm
      sync_q = synchronizer()
      sync_p = synchronizer()
      dset(self,"qnm",
         depend_array(name="qnm",
            value=np.zeros((self.nbeads,3*self.natoms), float),
               func={"q": (lambda : self.transform.b2nm(depstrip(self.beads.q)) ) },
                  synchro=sync_q ) )
      dset(self,"pnm",
         depend_array(name="pnm",
            value=np.zeros((self.nbeads,3*self.natoms), float),
               func={"p": (lambda : self.transform.b2nm(depstrip(self.beads.p)) ) },
                  synchro=sync_p ) )

      # must overwrite the functions
      dget(self.beads, "q")._func = { "qnm": (lambda : self.transform.nm2b(depstrip(self.qnm)) )  }
      dget(self.beads, "p")._func = { "pnm": (lambda : self.transform.nm2b(depstrip(self.pnm)) )  }
      dget(self.beads, "q").add_synchro(sync_q)
      dget(self.beads, "p").add_synchro(sync_p)

      # also within the "atomic" interface to beads
      for b in range(self.nbeads):
         dget(self.beads._blist[b],"q")._func = { "qnm": (lambda : self.transform.nm2b(depstrip(self.qnm)) )  }
         dget(self.beads._blist[b],"p")._func = { "pnm": (lambda : self.transform.nm2b(depstrip(self.pnm)) )  }
         dget(self.beads._blist[b],"q").add_synchro(sync_q)
         dget(self.beads._blist[b],"p").add_synchro(sync_p)


      # finally, we mark the beads as those containing the set positions
      dget(self.beads, "q").update_man()
      dget(self.beads, "p").update_man()
      
      # forces can be converted in nm representation, but here it makes no sense to set up a sync mechanism, 
      # as they always get computed in the bead rep
      if not self.forces is None: dset(self,"fnm", depend_array(name="fnm",
         value=np.zeros((self.nbeads,3*self.natoms), float),func=(lambda : self.transform.b2nm(depstrip(self.forces.f)) ),    
            dependencies=[dget(self.forces,"f")] ) )
      else: # have a fall-back plan when we don't want to initialize a force mechanism, e.g. for ring-polymer initialization         
         dset(self,"fnm", depend_array(name="fnm",
         value=np.zeros((self.nbeads,3*self.natoms), float),
         func=(lambda: depraise(ValueError("Cannot access NM forces when initializing the NM object without providing a force reference!") ) ),    
            dependencies=[] ) )
         
      # create path-frequencies related properties
      dset(self,"omegan",
         depend_value(name='omegan', func=self.get_omegan,
            dependencies=[dget(self.ensemble,"temp")]) )
      dset(self,"omegan2", depend_value(name='omegan2',func=self.get_omegan2,
            dependencies=[dget(self,"omegan")]) )
      dset(self,"omegak", depend_array(name='omegak',
         value=np.zeros(self.beads.nbeads,float),
            func=self.get_omegak, dependencies=[dget(self,"omegan")]) )
      dset(self,"omegak2", depend_array(name='omegak2',
         value=np.zeros(self.beads.nbeads,float),
            func=(lambda: (self.omegak)**2), dependencies=[dget(self,"omegak")]) )
            
      # sets up "dynamical" masses -- mass-scalings to give the correct RPMD/CMD dynamics
      # TODO: Do we really need different names and variable names? Seems confusing.
      dset(self,"nm_factor", depend_array(name="nmm",
         value=np.zeros(self.nbeads, float), func=self.get_nmm,
            dependencies=[dget(self,"nm_freqs"), dget(self,"mode") ]) )
      dset(self,"dynm3", depend_array(name="dm3",
         value=np.zeros((self.nbeads,3*self.natoms), float),func=self.get_dynm3,
            dependencies=[dget(self,"nm_factor"), dget(self.beads, "m3")] ) )
      dset(self,"dynomegak", depend_array(name="dynomegak",
         value=np.zeros(self.nbeads, float), func=self.get_dynwk,
            dependencies=[dget(self,"nm_factor"), dget(self,"omegak") ]) )

      dset(self, "dt", depend_value(name="dt", value = 1.0) )
      deppipe(self.motion, "dt", self, "dt")
      dset(self,"prop_pq",
         depend_array(name='prop_pq',value=np.zeros((self.beads.nbeads,2,2)),
            func=self.get_prop_pq,
               dependencies=[dget(self,"omegak"), dget(self,"nm_factor"), dget(self,"dt")]) )

      # if the mass matrix is not the RPMD one, the MD kinetic energy can't be
      # obtained in the bead representation because the masses are all mixed up
      dset(self,"kins",
         depend_array(name="kins",value=np.zeros(self.nbeads, float),
            func=self.get_kins,
               dependencies=[dget(self,"pnm"), dget(self.beads,"sm3"), dget(self, "nm_factor") ] ))
      dset(self,"kin",
         depend_value(name="kin", func=self.get_kin,
            dependencies=[dget(self,"kins")] ))
      dset(self,"kstress",
         depend_array(name="kstress",value=np.zeros((3,3), float),
            func=self.get_kstress,
               dependencies=[dget(self,"pnm"), dget(self.beads,"sm3"), dget(self, "nm_factor") ] ))

      # spring energy, calculated in normal modes
      dset(self, "vspring",
         depend_value(name="vspring",
            value=0.0,
            func=self.get_vspring,
            dependencies=[dget(self, "qnm"), dget(self, "omegak"), dget(self.beads, "m3")]))

      # spring forces on normal modes
      dset(self, "fspringnm",
         depend_array(name="fspringnm",
            value=np.zeros((self.nbeads, 3*self.natoms), float),
            func=self.get_fspringnm,
            dependencies=[dget(self, "qnm"), dget(self, "omegak"), dget(self.beads, "m3")]))

      # spring forces on beads, transformed from normal modes
      dset(self,"fspring",
         depend_array(name="fs",
            value=np.zeros((self.nbeads,3*self.natoms), float),
            func=(lambda: self.transform.nm2b(depstrip(self.fspringnm))),
            dependencies = [dget(self, "fspringnm")]))
Ejemplo n.º 5
0
   def bind(self, beads, ensemble):
      """ Initializes the normal modes object and binds to beads and ensemble.

      Do all the work down here as we need a full-formed necklace and ensemble
      to know how this should be done.

      Args:
         beads: A beads object to be bound.
         ensemble: An ensemble object to be bound.
      """

      self.nbeads = beads.nbeads
      self.natoms = beads.natoms

      # stores a reference to the bound beads and ensemble objects
      self.beads = beads
      self.ensemble = ensemble

      # sets up what's necessary to perform nm transformation.
      if self.transform_method == "fft":
         self.transform = nmtransform.nm_fft(nbeads=self.nbeads, natoms=self.natoms)
      elif self.transform_method == "matrix":
         self.transform = nmtransform.nm_trans(nbeads=self.nbeads)

      # creates arrays to store normal modes representation of the path.
      # must do a lot of piping to create "ex post" a synchronization between the beads and the nm
      sync_q = synchronizer()
      sync_p = synchronizer()
      dset(self,"qnm",
         depend_array(name="qnm",
            value=np.zeros((self.nbeads,3*self.natoms), float),
               func={"q": (lambda : self.transform.b2nm(depstrip(self.beads.q)) ) },
                  synchro=sync_q ) )
      dset(self,"pnm",
         depend_array(name="pnm",
            value=np.zeros((self.nbeads,3*self.natoms), float),
               func={"p": (lambda : self.transform.b2nm(depstrip(self.beads.p)) ) },
                  synchro=sync_p ) )

      # must overwrite the functions
      dget(self.beads, "q")._func = { "qnm": (lambda : self.transform.nm2b(depstrip(self.qnm)) )  }
      dget(self.beads, "p")._func = { "pnm": (lambda : self.transform.nm2b(depstrip(self.pnm)) )  }
      dget(self.beads, "q").add_synchro(sync_q)
      dget(self.beads, "p").add_synchro(sync_p)

      # also within the "atomic" interface to beads
      for b in range(self.nbeads):
         dget(self.beads._blist[b],"q")._func = { "qnm": (lambda : self.transform.nm2b(depstrip(self.qnm)) )  }
         dget(self.beads._blist[b],"p")._func = { "pnm": (lambda : self.transform.nm2b(depstrip(self.pnm)) )  }
         dget(self.beads._blist[b],"q").add_synchro(sync_q)
         dget(self.beads._blist[b],"p").add_synchro(sync_p)


      # finally, we mark the beads as those containing the set positions
      dget(self.beads, "q").update_man()
      dget(self.beads, "p").update_man()

      # create path-frequencies related properties
      dset(self,"omegan",
         depend_value(name='omegan', func=self.get_omegan,
            dependencies=[dget(self.ensemble,"temp")]) )
      dset(self,"omegan2", depend_value(name='omegan2',func=self.get_omegan2,
            dependencies=[dget(self,"omegan")]) )
      dset(self,"omegak", depend_array(name='omegak',
         value=np.zeros(self.beads.nbeads,float),
            func=self.get_omegak, dependencies=[dget(self,"omegan")]) )

      # sets up "dynamical" masses -- mass-scalings to give the correct RPMD/CMD dynamics
      dset(self,"nm_factor", depend_array(name="nmm",
         value=np.zeros(self.nbeads, float), func=self.get_nmm,
            dependencies=[dget(self,"nm_freqs"), dget(self,"mode") ]) )
      dset(self,"dynm3", depend_array(name="dm3",
         value=np.zeros((self.nbeads,3*self.natoms), float),func=self.get_dynm3,
            dependencies=[dget(self,"nm_factor"), dget(self.beads, "m3")] ) )
      dset(self,"dynomegak", depend_array(name="dynomegak",
         value=np.zeros(self.nbeads, float), func=self.get_dynwk,
            dependencies=[dget(self,"nm_factor"), dget(self,"omegak") ]) )

      dset(self,"prop_pq",
         depend_array(name='prop_pq',value=np.zeros((self.beads.nbeads,2,2)),
            func=self.get_prop_pq,
               dependencies=[dget(self,"omegak"), dget(self,"nm_factor"), dget(self.ensemble,"dt")]) )

      # if the mass matrix is not the RPMD one, the MD kinetic energy can't be
      # obtained in the bead representation because the masses are all mixed up
      dset(self,"kins",
         depend_array(name="kins",value=np.zeros(self.nbeads, float),
            func=self.get_kins,
               dependencies=[dget(self,"pnm"), dget(self.beads,"sm3"), dget(self, "nm_factor") ] ))
      dset(self,"kin",
         depend_value(name="kin", func=self.get_kin,
            dependencies=[dget(self,"kins")] ))
      dset(self,"kstress",
         depend_array(name="kstress",value=np.zeros((3,3), float),
            func=self.get_kstress,
               dependencies=[dget(self,"pnm"), dget(self.beads,"sm3"), dget(self, "nm_factor") ] ))