def build_tau(self):
        """Build the nonadiabatic coupling matrix, tau
        This routine assumes that S is already built"""

        c1i = (complex(0.0, 1.0))
        cm1i = (complex(0.0, -1.0))
        ntraj = self.get_num_traj_qm()
        self.tau = np.zeros((ntraj, ntraj), dtype=np.complex128)
        for key in self.centroids:
            keyi, keyj = str.split(key, "_a_")
            i = self.traj_map[keyi]
            j = self.traj_map[keyj]
            if i < ntraj and j < ntraj:
                istate = self.centroids[key].get_istate()
                jstate = self.centroids[key].get_jstate()
                if istate != jstate:
                    Sij = cg.overlap_nuc(self.traj[keyi],
                                         self.traj[keyj],
                                         positions_i="positions_qm",
                                         positions_j="positions_qm",
                                         momenta_i="momenta_qm",
                                         momenta_j="momenta_qm")
                    tdc = self.centroids[key].get_timederivcoups_qm()[jstate]
                    self.tau[i, j] = Sij * cm1i * tdc
                    self.tau[j, i] = Sij.conjugate() * c1i * tdc
    def update_centroids(self):
        """Compute the centroid positions and moment and check which centroids
        can be computed"""

        for key in self.centroids:
            key1, key2 = str.split(key, "_a_")
            timestep = self.centroids[key].get_timestep()

            # update backpropagating centroids
            self.centroids[key].set_z_compute_me_backprop(False)
            backprop_time = self.centroids[key].get_backprop_time() - timestep
            if (self.centroids[key].get_mintime() - 1.0e-6) < backprop_time:
                backprop_time1 = self.traj[key1].get_backprop_time()
                if (backprop_time > backprop_time1 - 1.0e-6)\
                        and (backprop_time1  < (self.traj[key1].get_firsttime() - 1.0e-6)\
                        or backprop_time1  < (self.traj[key1].get_mintime() + 1.0e-6)):
                    backprop_time2 = self.traj[key2].get_backprop_time()
                    if (backprop_time > backprop_time2 - 1.0e-6)\
                            and (backprop_time2  < (self.traj[key2].get_firsttime() - 1.0e-6)\
                            or backprop_time2  < (self.traj[key2].get_mintime() + 1.0e-6)):
                        time1 = self.traj[key1].get_time()
                        time2 = self.traj[key2].get_time()
                        # this if takes care of the special case where we try
                        # to compute the backpropagating centroid at firsttime before
                        # forward propagation has begun
                        if (backprop_time + 1.0e-6 <
                                time1) and (backprop_time + 1.0e-6 < time2):
                            pos1 = self.traj[key1].get_data_at_time_from_h5(
                                backprop_time, "positions")
                            mom1 = self.traj[key1].get_data_at_time_from_h5(
                                backprop_time, "momenta")
                            #                             if backprop_time2  < (self.traj[key2].get_mintime() + 1.0e-6):
                            #                                 pos2 = self.traj[key2].get_backprop_positions()
                            #                                 mom2 = self.traj[key2].get_backprop_momenta()
                            #                             else:
                            pos2 = self.traj[key2].get_data_at_time_from_h5(
                                backprop_time, "positions")
                            mom2 = self.traj[key2].get_data_at_time_from_h5(
                                backprop_time, "momenta")
                            #                             pos2, mom2 = self.traj[key2].get_q_and_p_at_time_from_h5(backprop_time)
                            absSij = abs(
                                cg.overlap_nuc(self.traj[key1],
                                               self.traj[key2],
                                               positions_i=pos1,
                                               positions_j=pos2,
                                               momenta_i=mom1,
                                               momenta_j=mom2))
                            #                             print "absSij", absSij
                            # this definition of mom is only right if all basis functions have same
                            # width!!!!  I don't think the momentum is every used but still we
                            # should fix this soon.
                            width1 = self.traj[key1].get_widths()
                            width2 = self.traj[key2].get_widths()
                            pos_cent = (width1 * pos1 +
                                        width2 * pos2) / (width1 + width2)
                            mom_cent = 0.5 * (mom1 + mom2)
                            self.centroids[key].set_backprop_positions(
                                pos_cent)
                            self.centroids[key].set_backprop_momenta(mom_cent)
                            if absSij > 0.001:
                                self.centroids[key].set_z_compute_me_backprop(
                                    True)
                            else:
                                self.centroids[key].set_backprop_time(
                                    backprop_time)
                                dt = self.centroids[key].get_timestep()
                                self.centroids[
                                    key].set_backprop_time_half_step(
                                        backprop_time + 0.5 * dt)
                                self.centroids[key].set_backprop_energies(
                                    np.zeros(
                                        self.centroids[key].get_numstates()))
                                self.centroids[key].set_backprop_timederivcoups(
                                    np.zeros(
                                        self.centroids[key].get_numstates()))
                                firsttime = self.centroids[key].get_firsttime()
                                if abs(backprop_time - firsttime) > 1.0e-6:
                                    self.centroids[key].h5_output(True)

            # update forward propagating centroids
            self.centroids[key].set_z_compute_me(False)
            time = self.centroids[key].get_time() + timestep
            if (self.centroids[key].get_maxtime() + timestep + 1.0e-6) > time:
                time1 = self.traj[key1].get_time()
                if (time < time1 + 1.0e-6
                    ) and time1 > self.traj[key1].get_firsttime() + 1.0e-6:
                    time2 = self.traj[key2].get_time()
                    if (time < time2 + 1.0e-6
                        ) and time2 > self.traj[key2].get_firsttime() + 1.0e-6:
                        pos1 = self.traj[key1].get_data_at_time_from_h5(
                            time, "positions")
                        mom1 = self.traj[key1].get_data_at_time_from_h5(
                            time, "momenta")
                        pos2 = self.traj[key2].get_data_at_time_from_h5(
                            time, "positions")
                        mom2 = self.traj[key2].get_data_at_time_from_h5(
                            time, "momenta")
                        #pos1, mom1 = self.traj[key1].get_q_and_p_at_time_from_h5(time)
                        #pos2, mom2 = self.traj[key2].get_q_and_p_at_time_from_h5(time)
                        absSij = abs(
                            cg.overlap_nuc(self.traj[key1],
                                           self.traj[key2],
                                           positions_i=pos1,
                                           positions_j=pos2,
                                           momenta_i=mom1,
                                           momenta_j=mom2))
                        #print "absSij", absSij
                        # this definion of mom is only correct if all basis functions have same
                        # width!!!!  I don't think that the centroid momentum is ever used, but
                        # we should still fix this soon
                        width1 = self.traj[key1].get_widths()
                        width2 = self.traj[key2].get_widths()
                        pos_cent = (width1 * pos1 + width2 * pos2) / (width1 +
                                                                      width2)
                        mom_cent = 0.5 * (mom1 + mom2)
                        self.centroids[key].set_positions(pos_cent)
                        self.centroids[key].set_momenta(mom_cent)
                        if absSij > 0.001:
                            self.centroids[key].set_z_compute_me(True)
                        else:
                            self.centroids[key].set_time(time)
                            dt = self.centroids[key].get_timestep()
                            self.centroids[key].set_time_half_step(time -
                                                                   0.5 * dt)
                            self.centroids[key].set_energies(
                                np.zeros(self.centroids[key].get_numstates()))
                            self.centroids[key].set_timederivcoups(
                                np.zeros(self.centroids[key].get_numstates()))
                            firsttime = self.centroids[key].get_firsttime()
                            if abs(time - firsttime) > 1.0e-6:
                                self.centroids[key].h5_output(False)
                            else:
                                self.centroids[key].h5_output(
                                    False, zdont_half_step=True)
Exemple #3
0
    def spawn_as_necessary(self):
        """this is the spawning routine"""

        spawntraj = dict()
        for key in self.traj:
            # trajectories that are spawning or should start were marked
            # during propagation.  See "propagate_step" and "consider_spawning"
            # in traj.py
            z = self.traj[key].get_z_spawn_now()
            z_dont = self.traj[key].get_z_dont_spawn()
            spawnt = self.traj[key].get_spawntimes()
            for jstate in range(self.traj[key].get_numstates()):
                # is this trajectory marked to spawn to state j?
                if z[jstate] > 0.5:
                    # create label that indicates parentage
                    # for example:
                    # a trajectory labeled 00b1b5 means that the initial
                    # trajectory "00" spawned a trajectory "1" (its
                    # second child) which then spawned another (it's 6th child)
                    label = str(self.traj[key].get_label() + "b" +
                                str(self.traj[key].get_numchildren()))

                    # create and initiate new trajectory structure
                    newtraj = traj(self.traj[key].numdims,
                                   self.traj[key].numstates)
                    newtraj.init_spawn_traj(self.traj[key], jstate, label)

                    # checking if overlap between parent and child is not too small
                    # sometimes NAC coupling jumps at points of electronic wf discontinuity
                    # even though it is a warning sign, it is inevitable in many cases
                    # so here we calculate nuclear overlap to make sure there is going to
                    # be population transfer as a result of adding newtraj
                    parent_child_nuc_olap = cg.overlap_nuc(
                        self.traj[key], newtraj)
                    if np.abs(parent_child_nuc_olap) < 0.05:
                        z_add_traj_olap = False
                    else:
                        z_add_traj_olap = True

                    # checking to see if overlap with existing trajectories
                    # is too high.  If so, we abort spawn
                    if z_add_traj_olap:
                        z_add_traj_olap = self.check_overlap(newtraj)

                    # rescaling velocity.  We'll abort if there is not
                    # enough energy (aka a "frustrated spawn")
                    z_add_traj_rescale = newtraj.rescale_momentum(
                        self.traj[key].get_energies_tmdt()[
                            self.traj[key].get_istate()])
                    # okay, now we finally decide whether to spawn or not
                    if z_add_traj_olap and z_add_traj_rescale:
                        print "## creating new trajectory ", label
                        spawntraj[label] = newtraj
                        self.traj[key].incr_numchildren()

                    # whether we spawn or not, we reset the trajectory so
                    # that:
                    # it isn't slated to spawn
                    z[jstate] = 0.0
                    # it shouldn't spawn again until the coupling drops
                    # below a threshold
                    z_dont[jstate] = 1.0
                    # it isn't currently spawning
                    spawnt[jstate] = -1.0

            # once all states have been checked, we update the TBF structure
            self.traj[key].set_z_spawn_now(z)
            self.traj[key].set_z_dont_spawn(z_dont)
            self.traj[key].set_spawntimes(spawnt)

        # okay, now it's time to add the spawned trajectories
        for label in spawntraj:
            # create new centroid structures
            for key2 in self.traj:
                # "_a_" marks the centroid labels
                centkey = str(key2 + "_a_" + label)

                # create and initiate the trajectory structures!
                newcent = traj(self.traj[key].numdims,
                               self.traj[key].numstates)
                newcent.init_centroid(self.traj[key2], spawntraj[label],
                                      centkey)

                # add the centroid
                self.centroids[centkey] = newcent
                print "# adding centroid ", centkey

            # finally, add the spawned trajectory
            self.add_traj(spawntraj[label])