コード例 #1
0
    def __init__(self, fields, dt=1000, molecule=None):
        # Create a Rotor object as the system of interest if not
        # provided by the user
        if molecule is None:
            ## System of interest
            ## Default: a Rotor object with quantum number = const.m
            self.molecule = Rotor(const.m)
        else:
            self.molecule = rotor
        ## Number of time points
        self.n = fields.shape[0]
        ## An nx2 np.ndarray containing the given field.
        ## Each row is the x- and y-component of such field at a time point.
        self.fields = fields
        field_const = 5.142 * 10**11 * 10**(-10)  #amplitude in V/angstrom
        self.fields = self.fields / field_const  #back to atomic units
        self._fields_list = [
            self.fields[i, :].flatten() for i in range(self.n)
        ]
        ## The resulting path from the given fields.
        self.path = np.zeros((self.n, 2))
        ## Time difference between two adjacent time points.
        self.dt = dt
        self._t_final = self.dt * self.n
        ## Time vector containing all time points.
        self.time = np.arange(self._t_final, step=self.dt, dtype=float)
        self.time_in_ps = self.time * 2.418e-5  #time in picoseconds

        #get and set initial field, but not using molecule.update_field()
        field = self._fields_list[0]
        self.molecule.set_field(field)
コード例 #2
0
    def setUp(self):
        """instantiation of Rotor object with quantum
        number m.
        
        """

        self.rotor = Rotor(const.m)
コード例 #3
0
    def __init__(self, path_desired, dt=1000, molecule=None):
        # Create a Rotor object as the system of interest if not
        # provided by the user
        if molecule is None:
            ## System of interest.
            ## Default value is a rotor (solver.molecule.Rotor)
            self.molecule = Rotor(const.m)
        else:
            self.molecule = rotor

        ## Path specified
        self.path = path_desired
        self._path_predicted = np.zeros_like(path_desired)
        ## Number of time points
        self.n = path_desired.shape[0]
        ## Delta t between two adjacent time points.
        self.dt = dt
        self._t_final = self.n * self.dt
        ## Time vector in unit of ?
        self.time = np.arange(self._t_final, step=self.dt, dtype=float)
        self._ddpath = np.stack((f.d2dt2(
            self.path[:, 0], self.dt), f.d2dt2(self.path[:, 1], self.dt)),
                                axis=1)

        # operators used only by private methods within class instance
        m = self.molecule.m
        self._op1 = (f.cosphi(m) + 4 * f.sinphi(m) @ f.ddphi(m) -
                     4 * f.cosphi(m) @ f.d2dphi2(m))
        self._op2 = (f.sinphi(m) - 4 * f.cosphi(m) @ f.ddphi(m) -
                     4 * f.sinphi(m) @ f.d2dphi2(m))
        self._cosphi2 = f.cosphi(m) @ f.cosphi(m)
        self._sinphi2 = f.sinphi(m) @ f.sinphi(m)
        self._cosphi_sinphi = f.cosphi(m) @ f.sinphi(m)
        self._sinphi_cosphi = f.sinphi(m) @ f.cosphi(m)

        #calc and set initial field, but not using molecule.update_field()
        field = self._get_field(0, real=True)
        self.molecule.set_field(field)
コード例 #4
0
    def setUp(self):
        """init system with test data for sigmoid"""

        self.rotor = Rotor(const.m)

        fname_fields = 'testdata_solver/fields_real_for_sigmoid_path.txt'
        fname_states = 'testdata_solver/states_for_sigmoid_path.txt'
        self.fields = np.genfromtxt(fname_fields, dtype=float, delimiter=',')
        self.states_expected = np.genfromtxt(fname_states,
                                             dtype=float,
                                             delimiter=',')

        n = 100000
        rotor_period = 2 * np.pi * const.hbar / const.B
        self.t_final = 100 * rotor_period / (2 * np.pi)
        self.dt = self.t_final / n
        self.time = np.arange(self.t_final, step=self.dt, dtype=float)
コード例 #5
0
class PathToField(Solver):
    """PathToField is a solver that solves the control fields for a 
    given path of dipole moment projection.

    Class PathToField is used to solve a set of control fields that
    drive the dipole moment projection of the system of interest to 
    follow a given path. The system of interest by default is a rotor 
    (molecule.Rotor.)  

    Parameters
    ----------
    path_desired: numpy.array, shape=(n,2)
        A desired path of molecule dipole moment projection.

    dt: float, optional (default=1000)
        Difference of time between two adjacent time points. This is 
        path-specific and is currently calculated when a 
        dataContainer.DataContainer object is instantiated with a
        desired path.

    molecule: Molecule object, optional (default=Rotor)
        System of interest. Default to a Rotor molecule with a system 
        dimension of m=8 specified in constants.py.

    Attributes
    ----------
    molecule: Molecule object
        System of interest.

    path: numpy.array, shape=(n,2)
        Path specified.

    n: int
        Number of time points.

    dt: float
        Delta t between two adjacent time points.

    time: numpy.array, shape=(n,)
        Time vector in atomic units.

    """
    def __init__(self, path_desired, dt=1000, molecule=None):
        # Create a Rotor object as the system of interest if not
        # provided by the user
        if molecule is None:
            ## System of interest.
            ## Default value is a rotor (solver.molecule.Rotor)
            self.molecule = Rotor(const.m)
        else:
            self.molecule = rotor

        ## Path specified
        self.path = path_desired
        self._path_predicted = np.zeros_like(path_desired)
        ## Number of time points
        self.n = path_desired.shape[0]
        ## Delta t between two adjacent time points.
        self.dt = dt
        self._t_final = self.n * self.dt
        ## Time vector in unit of ?
        self.time = np.arange(self._t_final, step=self.dt, dtype=float)
        self._ddpath = np.stack((f.d2dt2(
            self.path[:, 0], self.dt), f.d2dt2(self.path[:, 1], self.dt)),
                                axis=1)

        # operators used only by private methods within class instance
        m = self.molecule.m
        self._op1 = (f.cosphi(m) + 4 * f.sinphi(m) @ f.ddphi(m) -
                     4 * f.cosphi(m) @ f.d2dphi2(m))
        self._op2 = (f.sinphi(m) - 4 * f.cosphi(m) @ f.ddphi(m) -
                     4 * f.sinphi(m) @ f.d2dphi2(m))
        self._cosphi2 = f.cosphi(m) @ f.cosphi(m)
        self._sinphi2 = f.sinphi(m) @ f.sinphi(m)
        self._cosphi_sinphi = f.cosphi(m) @ f.sinphi(m)
        self._sinphi_cosphi = f.sinphi(m) @ f.cosphi(m)

        #calc and set initial field, but not using molecule.update_field()
        field = self._get_field(0, real=True)
        self.molecule.set_field(field)

    def solve(self):
        """Calculate the control field required for each time step.
        """

        for j in tqdm.tqdm(range(1, self.n)):
            self.molecule.evolve(self.dt)
            field = self._get_field(j, real=True)
            self.molecule.update_field(field)

        # self._velidate()

    def export(self):
        """Export calculated time vector, fields, path, and states 
        as np.ndarray.

        Returns
        -------
        time: numpy.array, shape=(n,)
            Time vector based on dt. In unit of picoseconds.

        fields: numpy.array, shape=(n,2) 
            Control fields required for the path of interest. In 
            unit of V/angstrom.

        path: numpy.array, shape=(n,2)
            Resulting path based on the calculated fields.

        states: numpy.array, shape=(2m+1,n)
            State amplitudes of the system at every time point.

        """

        time = self.molecule.get_time_asarray()
        time = time * 2.418 * 10**(-17) * 10**12  #time in picoseconds

        states = self.molecule.get_states_asarray()

        fields = self.molecule.get_fields_asarray()
        field_const = 5.142 * 10**11 * 10**(-10)  #amplitude in V/angstrom
        fields = fields * field_const

        path = np.zeros((self.n, 2))
        oper_x = self.molecule.dipole_x
        oper_y = self.molecule.dipole_y
        states_list = self.molecule.history['state']
        for i in range(self.n):
            path[i, 0] = states_list[i].get_expt(oper_x).real
            path[i, 1] = states_list[i].get_expt(oper_y).real

        return time, fields, path, states

    def _get_field(self, j, real=False):
        """Calculate the required field for the next step.

        Parameters
        ----------
        j: int
            System is at the j-th time point.

        real: bool, optional (default=False)
            If True, force the returned value to be only the real 
            part of a complex number.

        Returns
        -------
        field: numpy.array, shape=(2,)
            An array of size 2 containing x- and y-component of the
            control field for the next step.

        """

        field = self._get_Ainv() @ self._get_b(j)
        if real:
            field = field.real
        return field.flatten()

    def _get_det(self):
        """Calculate determinant of matrix A"""
        state = self.molecule.state
        c = 4 * const.B**2 * const.mu**2 / const.hbar**4
        det = (c *
               (state.get_expt(self._sinphi2) * state.get_expt(self._cosphi2) -
                state.get_expt(self._sinphi_cosphi)**2))
        return det

    def _get_Ainv(self):
        """Calculate inverse of matrix A"""
        state = self.molecule.state
        c = 2 * const.B * const.mu / const.hbar**2
        a11 = c * state.get_expt(self._sinphi2)
        a12 = -c * state.get_expt(self._cosphi_sinphi)
        a21 = -c * state.get_expt(self._sinphi_cosphi)
        a22 = c * state.get_expt(self._cosphi2)
        det = self._get_det()
        A_inv = 1 / det * np.array([[a22, -a12], [-a21, a11]])
        return A_inv

    def _get_b(self, i):
        """Calculate b vector"""
        state = self.molecule.state
        c = const.B**2 / const.hbar**2
        b1 = self._ddpath[i, 0] + np.real(c * state.get_expt(self._op1))
        b2 = self._ddpath[i, 1] + np.real(c * state.get_expt(self._op2))
        return np.array([b1, b2])
コード例 #6
0
class FieldToPath(Solver):
    """Calculate the resulting path from a given set of control fields.
    
    Class FieldToPath is used to solve the trajectory of molecule's 
    dipole moment projection for a given set of control fields in 
    time. The system of interest by default is a rotor 
    (molecule.Rotor.) 

    Parameters
    ----------
    fields: numpy.array, shape=(n,2)
        A prescribed set of control fields to apply to the molecule.

    dt: float, optional (default=1000)
        Difference of time between two adjacent time points. This is 
        path-specific and is currently calculated when a 
        dataContainer.DataContainer object is instantiated with a
        desired path.

    molecule: Molecule object, optional (default=Rotor)
        System of interest. Default to a Rotor molecule with a system 
        dimension of m=8 specified in constants.py.

    Attributes
    ----------
    molecule: Molecule object
        System of interest.

    n: int
        Number of time points.

    fields: numpy.array, shape=(n,2)
        Time-series of control field prescribed.

    dt: float
        Delta t between two adjacent time points.

    time: numpy.array, shape=(n,)
        Time vector in atomic units.

    path: numpy.array, shape=(n,2)
        Resulting path of molecule's dipole moment projection.

    """
    def __init__(self, fields, dt=1000, molecule=None):
        # Create a Rotor object as the system of interest if not
        # provided by the user
        if molecule is None:
            ## System of interest
            ## Default: a Rotor object with quantum number = const.m
            self.molecule = Rotor(const.m)
        else:
            self.molecule = rotor
        ## Number of time points
        self.n = fields.shape[0]
        ## An nx2 np.ndarray containing the given field.
        ## Each row is the x- and y-component of such field at a time point.
        self.fields = fields
        field_const = 5.142 * 10**11 * 10**(-10)  #amplitude in V/angstrom
        self.fields = self.fields / field_const  #back to atomic units
        self._fields_list = [
            self.fields[i, :].flatten() for i in range(self.n)
        ]
        ## The resulting path from the given fields.
        self.path = np.zeros((self.n, 2))
        ## Time difference between two adjacent time points.
        self.dt = dt
        self._t_final = self.dt * self.n
        ## Time vector containing all time points.
        self.time = np.arange(self._t_final, step=self.dt, dtype=float)
        self.time_in_ps = self.time * 2.418e-5  #time in picoseconds

        #get and set initial field, but not using molecule.update_field()
        field = self._fields_list[0]
        self.molecule.set_field(field)

    def solve(self):
        """Calculate path of rotor dipole moment projection from 
        given fields.

        """

        for i in tqdm.tqdm(range(1, self.n)):
            self.molecule.evolve(self.dt)
            self.molecule.set_field(self._fields_list[i])

    def export(self):
        """Export calculated time vector, fields, and states as 
        np.ndarray.

        Returns
        -------
        time: numpy.array, shape=(n,)
            Time vector based on dt. In unit of picoseconds.

        path: numpy.array, shape=(n,2)
            Resulting path of molecule's dipole moment projection.

        states: numpy.array, shape=(2m+1,n)
            State amplitudes of the system at every time point.
        
        """

        time = self.molecule.get_time_asarray()
        # time = self.time
        states = self.molecule.get_states_asarray()
        states_list = self.molecule.history['state']
        path = np.zeros((self.n, 2))
        oper_x = self.molecule.dipole_x
        oper_y = self.molecule.dipole_y
        for i in range(self.n):
            path[i, 0] = states_list[i].get_expt(oper_x).real
            path[i, 1] = states_list[i].get_expt(oper_y).real

        return time, path, states
コード例 #7
0
class test_molecule(unittest.TestCase):
    """Testing class for abstract base class Molecules.

    """
    def setUp(self):
        """Instantiate rotor object with quantum number m."""

        self.rotor = Rotor(const.m)

    def test_rotor_init(self):
        """Test rotor init function with state array generated."""

        state_prob = np.zeros(2 * const.m + 1)
        state_prob[const.m] = 1
        np.testing.assert_array_equal(self.rotor.state.value, state_prob)

    def test_update_attr(self):
        """Test update functions to update attributes of Rotor"""

        self.rotor.update_time(1.0)
        self.rotor.update_state(State(const.m))
        self.rotor.update_field(np.array([1, 1]))
        for attr in self.rotor.history:
            self.assertTrue(len(self.rotor.history[attr]) == 2)

    def test_evolve(self):
        """Test evolve function over 5 timesteps and the corresponding
        history of state array generated.
        
        """

        for i in range(5):
            self.rotor.evolve(0.1)
        self.assertTrue(len(self.rotor.history['state']) == 6)

    def test_get_history_asarray(self):
        """Test function to return history of states as array."""

        for i in range(5):
            self.rotor.evolve(0.1)
            self.rotor.update_field(np.array([0, 0]))
        self.assertEqual(self.rotor.get_states_asarray().shape,
                         (2 * const.m + 1, 6))
        self.assertEqual(self.rotor.get_fields_asarray().shape, (6, 2))