qrotor.system

Description

The System object contains all the information needed for a single QRotor calculation. This class can be loaded directly as qrotor.System().


  1"""
  2# Description
  3
  4The `System` object contains all the information needed for a single QRotor calculation.
  5This class can be loaded directly as `qrotor.System()`.
  6
  7---
  8"""
  9
 10
 11import numpy as np
 12from .constants import *
 13from aton import alias
 14from ._version import __version__
 15
 16
 17class System:
 18    """Quantum system.
 19
 20    Contains all the data for a single QRotor calculation, with both inputs and outputs.
 21
 22    Energy units are in meV and angles are in radians, unless stated otherwise.
 23    """
 24    def __init__(
 25            self,
 26            comment: str = None,
 27            B: float = B_CH3,
 28            gridsize: int = 200000,
 29            searched_E: int = 21,
 30            correct_potential_offset: bool = True,
 31            save_eigenvectors: bool = True,
 32            potential_name: str = '',
 33            potential_constants: list = None,
 34            tags: str = '',
 35            ):
 36        """A new quantum system can be instantiated as `system = qrotor.System()`.
 37        This new system will contain the default values listed above.
 38        """
 39        ## Technical
 40        self.version = __version__
 41        """Version of the package used to generate the data."""
 42        self.comment: str = comment
 43        """Custom comment for the dataset."""
 44        self.searched_E: int = searched_E
 45        """Number of energy eigenvalues to be searched."""
 46        self.correct_potential_offset: bool = correct_potential_offset
 47        """Correct the potential offset as `V - min(V)` or not."""
 48        self.save_eigenvectors: bool = save_eigenvectors
 49        """Save or not the eigenvectors. Final file size will be bigger."""
 50        self.tags: str = tags
 51        """Custom tags separated by spaces, such as the molecular group, etc.
 52
 53        Can be used to filter between datasets.
 54        """
 55        ## Potential
 56        self.B: float = B
 57        """Kinetic rotational energy, as in $B=\\frac{\\hbar^2}{2I}$.
 58
 59        Defaults to the value for a methyl group.
 60        """
 61        self.gridsize: int = gridsize
 62        """Number of points in the grid."""
 63        self.grid = []
 64        """The grid with the points to be used in the calculation.
 65
 66        Can be set automatically over $2 \\pi$ with `System.set_grid()`.
 67        Units must be in radians.
 68        """
 69        self.potential_name: str = potential_name
 70        """Name of the desired potential: `'zero'`, `'titov2023'`, `'test'`...
 71
 72        If empty or unrecognised, the custom potential values inside `System.potential_values` will be used. 
 73        """
 74        self.potential_constants: list = potential_constants
 75        """List of constants to be used in the calculation of the potential energy, in the `qrotor.potential` module."""
 76        self.potential_values = []
 77        """Numpy [ndarray](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html) with the potential values for each point in the grid.
 78
 79        Can be calculated with a function available in the `qrotor.potential` module,
 80        or loaded externally with the `qrotor.potential.load()` function.
 81        Potential energy units must be in meV.
 82        """
 83        # Potential values determined upon solving
 84        self.potential_offset: float = None
 85        """`min(V)` before offset correction when `correct_potential_offset = True`"""
 86        self.potential_min: float = None
 87        """`min(V)`"""
 88        self.potential_max: float = None
 89        """`max(V)`"""
 90        # Energies determined upon solving
 91        self.eigenvectors = []
 92        """Eigenvectors, if `save_eigenvectors` is True. Beware of the file size."""
 93        self.eigenvalues = []
 94        """Calculated eigenvalues of the system. In meV."""
 95        self.E_levels: list = []
 96        """List of `eigenvalues` grouped by energy levels, found below `potential_max`."""
 97        self.deg: float = None
 98        """Estimated degeneracy of the `E_levels` found below `potential_max`."""
 99        self.E_activation: float = None
100        """Activation energy or energy barrier, from the ground torsional state to the top of the potential barrier, `max(V) - min(eigenvalues)`"""
101        self.excitations: list = []
102        """Torsional excitations, as the difference between each energy level with respect to the ground state.
103
104        Considers the means between degenerated eigenvalues for all energy levels below `potential_max`.
105        """
106        self.splittings: list = []
107        """Tunnel splitting energies, for every degenerated energy level.
108        
109        Calculated for all `E_levels` as the difference between
110        the mean of the eigenvalues from A and the mean of the eigenvalues from E,
111        see [R. M. Dimeo, American Journal of Physics 71, 885–893 (2003)](https://doi.org/10.1119/1.1538575).
112        """
113        self.runtime: float = None
114        """Time taken to solve the eigenvalues."""
115
116    def solve(self, new_gridsize:int=None):
117        """Default user method to solve the quantum system.
118
119        The potential can be interpolated to a `new_gridsize`.
120
121        Same as running `qrotor.solve.energies(System)`
122        with an optional new gridsize.
123        """
124        from .solve import energies
125        if new_gridsize:
126            self.gridsize = new_gridsize
127        return energies(self)
128
129    def solve_potential(self, new_gridsize:int=None):
130        """Default user method to quickly solve the potential of the quantum system.
131
132        This method does not solve the energies of the system,
133        it just computes the potential and sets `System.potential_max`,
134        `System.potential_min` and `System.potential_offset` accordingly.
135        To solve the potential AND the energies, check `System.solve()`.
136
137        The potential can be interpolated to a `new_gridsize`.
138
139        Same as running `qrotor.solve.potential(System)`
140        with an optional new gridsize.
141        """
142        from .solve import potential
143        if new_gridsize:
144            self.gridsize = new_gridsize
145        return potential(self)
146
147    def change_phase(self, phase:float, calculate:bool=True):
148        """Apply a phase shift to the grid and potential values.
149
150        The `phase` should be a multiple of $\\pi$ (e.g., 3/2 for $3\\pi/2$).
151        The resulting grid will be expressed between $-2\\pi$ and $2\\pi$.
152
153        The System is solved immediately after the phase change.
154        This last step ensures that all eigenvalues and wavefunctions are correct.
155        You can override this step with `calculate = False`,
156        but remember to solve the System later!
157        """
158        if not any(self.potential_values) or not any(self.grid):
159            raise ValueError("System.potential_values and System.grid must be set before applying a phase shift.")
160        # Normalise the phase between 0 and 2
161        if abs(phase) >= 2:
162            phase = phase % 2
163        while phase < 0:
164            phase = phase + 2
165        # Shift the grid, between -2pi and 2pi
166        self.grid = (self.grid + (phase * np.pi))
167        # Apply the phase shift to potential values
168        phase_points = int((phase / 2) * self.gridsize)
169        self.potential_values = np.roll(self.potential_values, phase_points)
170        # Check that the grid is still within -2pi and 2pi, otherwise normalise it for a final time
171        while self.grid[0] <= (-2 * np.pi + 0.1):  # With a small tolerance
172            self.grid = self.grid + 2 * np.pi
173        while self.grid[-1] >= 2.5 * np.pi:  # It was not a problem until reaching 5/2 pi
174            self.grid = self.grid -2 * np.pi
175        print(f'Potential shifted by {phase}π')
176        if calculate:
177            self.solve()
178        return self
179
180    def set_grid(self, gridsize:int=None):
181        """Sets the `System.grid` to the specified `gridsize` from 0 to $2\\pi$.
182
183        If the system had a previous grid and potential values,
184        it will interpolate those values to the new gridsize,
185        using `qrotor.potential.interpolate()`.
186        """
187        if gridsize == self.gridsize:
188            return self  # Nothing to do here
189        if gridsize:
190            self.gridsize = gridsize
191        # Should we interpolate?
192        if any(self.potential_values) and any(self.grid) and self.gridsize:
193            from .potential import interpolate
194            self = interpolate(self)
195        # Should we create the values from zero?
196        elif self.gridsize:
197                self.grid = np.linspace(0, 2*np.pi, self.gridsize)
198        else:
199            raise ValueError('gridsize must be provided if there is no System.gridsize')
200        return self
201
202    def reduce_size(self):
203        """Discard data that takes too much space,
204        like eigenvectors, potential values and grids."""
205        self.eigenvectors = []
206        self.potential_values = []
207        self.grid = []
208        return self
209
210    def summary(self):
211        """Returns a dict with a summary of the System data."""
212        return {
213            'version': self.version,
214            'comment': self.comment,
215            'tags': self.tags,
216            'searched_E': self.searched_E,
217            'correct_potential_offset': self.correct_potential_offset,
218            'save_eigenvectors': self.save_eigenvectors,
219            'B': self.B,
220            'gridsize': self.gridsize,
221            'potential_name': self.potential_name,
222            'potential_constants': self.potential_constants.tolist() if isinstance(self.potential_constants, np.ndarray) else self.potential_constants,
223            'potential_offset': self.potential_offset,
224            'potential_min': self.potential_min,
225            'potential_max': self.potential_max,
226            'eigenvalues': self.eigenvalues.tolist() if isinstance(self.eigenvalues, np.ndarray) else self.eigenvalues,
227            'E_levels': self.E_levels,
228            'deg': self.deg,
229            'excitations': self.excitations,
230            'splittings': self.splittings,
231            'E_activation': self.E_activation,
232            'runtime': self.runtime,
233        }
class System:
 18class System:
 19    """Quantum system.
 20
 21    Contains all the data for a single QRotor calculation, with both inputs and outputs.
 22
 23    Energy units are in meV and angles are in radians, unless stated otherwise.
 24    """
 25    def __init__(
 26            self,
 27            comment: str = None,
 28            B: float = B_CH3,
 29            gridsize: int = 200000,
 30            searched_E: int = 21,
 31            correct_potential_offset: bool = True,
 32            save_eigenvectors: bool = True,
 33            potential_name: str = '',
 34            potential_constants: list = None,
 35            tags: str = '',
 36            ):
 37        """A new quantum system can be instantiated as `system = qrotor.System()`.
 38        This new system will contain the default values listed above.
 39        """
 40        ## Technical
 41        self.version = __version__
 42        """Version of the package used to generate the data."""
 43        self.comment: str = comment
 44        """Custom comment for the dataset."""
 45        self.searched_E: int = searched_E
 46        """Number of energy eigenvalues to be searched."""
 47        self.correct_potential_offset: bool = correct_potential_offset
 48        """Correct the potential offset as `V - min(V)` or not."""
 49        self.save_eigenvectors: bool = save_eigenvectors
 50        """Save or not the eigenvectors. Final file size will be bigger."""
 51        self.tags: str = tags
 52        """Custom tags separated by spaces, such as the molecular group, etc.
 53
 54        Can be used to filter between datasets.
 55        """
 56        ## Potential
 57        self.B: float = B
 58        """Kinetic rotational energy, as in $B=\\frac{\\hbar^2}{2I}$.
 59
 60        Defaults to the value for a methyl group.
 61        """
 62        self.gridsize: int = gridsize
 63        """Number of points in the grid."""
 64        self.grid = []
 65        """The grid with the points to be used in the calculation.
 66
 67        Can be set automatically over $2 \\pi$ with `System.set_grid()`.
 68        Units must be in radians.
 69        """
 70        self.potential_name: str = potential_name
 71        """Name of the desired potential: `'zero'`, `'titov2023'`, `'test'`...
 72
 73        If empty or unrecognised, the custom potential values inside `System.potential_values` will be used. 
 74        """
 75        self.potential_constants: list = potential_constants
 76        """List of constants to be used in the calculation of the potential energy, in the `qrotor.potential` module."""
 77        self.potential_values = []
 78        """Numpy [ndarray](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html) with the potential values for each point in the grid.
 79
 80        Can be calculated with a function available in the `qrotor.potential` module,
 81        or loaded externally with the `qrotor.potential.load()` function.
 82        Potential energy units must be in meV.
 83        """
 84        # Potential values determined upon solving
 85        self.potential_offset: float = None
 86        """`min(V)` before offset correction when `correct_potential_offset = True`"""
 87        self.potential_min: float = None
 88        """`min(V)`"""
 89        self.potential_max: float = None
 90        """`max(V)`"""
 91        # Energies determined upon solving
 92        self.eigenvectors = []
 93        """Eigenvectors, if `save_eigenvectors` is True. Beware of the file size."""
 94        self.eigenvalues = []
 95        """Calculated eigenvalues of the system. In meV."""
 96        self.E_levels: list = []
 97        """List of `eigenvalues` grouped by energy levels, found below `potential_max`."""
 98        self.deg: float = None
 99        """Estimated degeneracy of the `E_levels` found below `potential_max`."""
100        self.E_activation: float = None
101        """Activation energy or energy barrier, from the ground torsional state to the top of the potential barrier, `max(V) - min(eigenvalues)`"""
102        self.excitations: list = []
103        """Torsional excitations, as the difference between each energy level with respect to the ground state.
104
105        Considers the means between degenerated eigenvalues for all energy levels below `potential_max`.
106        """
107        self.splittings: list = []
108        """Tunnel splitting energies, for every degenerated energy level.
109        
110        Calculated for all `E_levels` as the difference between
111        the mean of the eigenvalues from A and the mean of the eigenvalues from E,
112        see [R. M. Dimeo, American Journal of Physics 71, 885–893 (2003)](https://doi.org/10.1119/1.1538575).
113        """
114        self.runtime: float = None
115        """Time taken to solve the eigenvalues."""
116
117    def solve(self, new_gridsize:int=None):
118        """Default user method to solve the quantum system.
119
120        The potential can be interpolated to a `new_gridsize`.
121
122        Same as running `qrotor.solve.energies(System)`
123        with an optional new gridsize.
124        """
125        from .solve import energies
126        if new_gridsize:
127            self.gridsize = new_gridsize
128        return energies(self)
129
130    def solve_potential(self, new_gridsize:int=None):
131        """Default user method to quickly solve the potential of the quantum system.
132
133        This method does not solve the energies of the system,
134        it just computes the potential and sets `System.potential_max`,
135        `System.potential_min` and `System.potential_offset` accordingly.
136        To solve the potential AND the energies, check `System.solve()`.
137
138        The potential can be interpolated to a `new_gridsize`.
139
140        Same as running `qrotor.solve.potential(System)`
141        with an optional new gridsize.
142        """
143        from .solve import potential
144        if new_gridsize:
145            self.gridsize = new_gridsize
146        return potential(self)
147
148    def change_phase(self, phase:float, calculate:bool=True):
149        """Apply a phase shift to the grid and potential values.
150
151        The `phase` should be a multiple of $\\pi$ (e.g., 3/2 for $3\\pi/2$).
152        The resulting grid will be expressed between $-2\\pi$ and $2\\pi$.
153
154        The System is solved immediately after the phase change.
155        This last step ensures that all eigenvalues and wavefunctions are correct.
156        You can override this step with `calculate = False`,
157        but remember to solve the System later!
158        """
159        if not any(self.potential_values) or not any(self.grid):
160            raise ValueError("System.potential_values and System.grid must be set before applying a phase shift.")
161        # Normalise the phase between 0 and 2
162        if abs(phase) >= 2:
163            phase = phase % 2
164        while phase < 0:
165            phase = phase + 2
166        # Shift the grid, between -2pi and 2pi
167        self.grid = (self.grid + (phase * np.pi))
168        # Apply the phase shift to potential values
169        phase_points = int((phase / 2) * self.gridsize)
170        self.potential_values = np.roll(self.potential_values, phase_points)
171        # Check that the grid is still within -2pi and 2pi, otherwise normalise it for a final time
172        while self.grid[0] <= (-2 * np.pi + 0.1):  # With a small tolerance
173            self.grid = self.grid + 2 * np.pi
174        while self.grid[-1] >= 2.5 * np.pi:  # It was not a problem until reaching 5/2 pi
175            self.grid = self.grid -2 * np.pi
176        print(f'Potential shifted by {phase}π')
177        if calculate:
178            self.solve()
179        return self
180
181    def set_grid(self, gridsize:int=None):
182        """Sets the `System.grid` to the specified `gridsize` from 0 to $2\\pi$.
183
184        If the system had a previous grid and potential values,
185        it will interpolate those values to the new gridsize,
186        using `qrotor.potential.interpolate()`.
187        """
188        if gridsize == self.gridsize:
189            return self  # Nothing to do here
190        if gridsize:
191            self.gridsize = gridsize
192        # Should we interpolate?
193        if any(self.potential_values) and any(self.grid) and self.gridsize:
194            from .potential import interpolate
195            self = interpolate(self)
196        # Should we create the values from zero?
197        elif self.gridsize:
198                self.grid = np.linspace(0, 2*np.pi, self.gridsize)
199        else:
200            raise ValueError('gridsize must be provided if there is no System.gridsize')
201        return self
202
203    def reduce_size(self):
204        """Discard data that takes too much space,
205        like eigenvectors, potential values and grids."""
206        self.eigenvectors = []
207        self.potential_values = []
208        self.grid = []
209        return self
210
211    def summary(self):
212        """Returns a dict with a summary of the System data."""
213        return {
214            'version': self.version,
215            'comment': self.comment,
216            'tags': self.tags,
217            'searched_E': self.searched_E,
218            'correct_potential_offset': self.correct_potential_offset,
219            'save_eigenvectors': self.save_eigenvectors,
220            'B': self.B,
221            'gridsize': self.gridsize,
222            'potential_name': self.potential_name,
223            'potential_constants': self.potential_constants.tolist() if isinstance(self.potential_constants, np.ndarray) else self.potential_constants,
224            'potential_offset': self.potential_offset,
225            'potential_min': self.potential_min,
226            'potential_max': self.potential_max,
227            'eigenvalues': self.eigenvalues.tolist() if isinstance(self.eigenvalues, np.ndarray) else self.eigenvalues,
228            'E_levels': self.E_levels,
229            'deg': self.deg,
230            'excitations': self.excitations,
231            'splittings': self.splittings,
232            'E_activation': self.E_activation,
233            'runtime': self.runtime,
234        }

Quantum system.

Contains all the data for a single QRotor calculation, with both inputs and outputs.

Energy units are in meV and angles are in radians, unless stated otherwise.

System( comment: str = None, B: float = np.float64(0.6451810934439263), gridsize: int = 200000, searched_E: int = 21, correct_potential_offset: bool = True, save_eigenvectors: bool = True, potential_name: str = '', potential_constants: list = None, tags: str = '')
 25    def __init__(
 26            self,
 27            comment: str = None,
 28            B: float = B_CH3,
 29            gridsize: int = 200000,
 30            searched_E: int = 21,
 31            correct_potential_offset: bool = True,
 32            save_eigenvectors: bool = True,
 33            potential_name: str = '',
 34            potential_constants: list = None,
 35            tags: str = '',
 36            ):
 37        """A new quantum system can be instantiated as `system = qrotor.System()`.
 38        This new system will contain the default values listed above.
 39        """
 40        ## Technical
 41        self.version = __version__
 42        """Version of the package used to generate the data."""
 43        self.comment: str = comment
 44        """Custom comment for the dataset."""
 45        self.searched_E: int = searched_E
 46        """Number of energy eigenvalues to be searched."""
 47        self.correct_potential_offset: bool = correct_potential_offset
 48        """Correct the potential offset as `V - min(V)` or not."""
 49        self.save_eigenvectors: bool = save_eigenvectors
 50        """Save or not the eigenvectors. Final file size will be bigger."""
 51        self.tags: str = tags
 52        """Custom tags separated by spaces, such as the molecular group, etc.
 53
 54        Can be used to filter between datasets.
 55        """
 56        ## Potential
 57        self.B: float = B
 58        """Kinetic rotational energy, as in $B=\\frac{\\hbar^2}{2I}$.
 59
 60        Defaults to the value for a methyl group.
 61        """
 62        self.gridsize: int = gridsize
 63        """Number of points in the grid."""
 64        self.grid = []
 65        """The grid with the points to be used in the calculation.
 66
 67        Can be set automatically over $2 \\pi$ with `System.set_grid()`.
 68        Units must be in radians.
 69        """
 70        self.potential_name: str = potential_name
 71        """Name of the desired potential: `'zero'`, `'titov2023'`, `'test'`...
 72
 73        If empty or unrecognised, the custom potential values inside `System.potential_values` will be used. 
 74        """
 75        self.potential_constants: list = potential_constants
 76        """List of constants to be used in the calculation of the potential energy, in the `qrotor.potential` module."""
 77        self.potential_values = []
 78        """Numpy [ndarray](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html) with the potential values for each point in the grid.
 79
 80        Can be calculated with a function available in the `qrotor.potential` module,
 81        or loaded externally with the `qrotor.potential.load()` function.
 82        Potential energy units must be in meV.
 83        """
 84        # Potential values determined upon solving
 85        self.potential_offset: float = None
 86        """`min(V)` before offset correction when `correct_potential_offset = True`"""
 87        self.potential_min: float = None
 88        """`min(V)`"""
 89        self.potential_max: float = None
 90        """`max(V)`"""
 91        # Energies determined upon solving
 92        self.eigenvectors = []
 93        """Eigenvectors, if `save_eigenvectors` is True. Beware of the file size."""
 94        self.eigenvalues = []
 95        """Calculated eigenvalues of the system. In meV."""
 96        self.E_levels: list = []
 97        """List of `eigenvalues` grouped by energy levels, found below `potential_max`."""
 98        self.deg: float = None
 99        """Estimated degeneracy of the `E_levels` found below `potential_max`."""
100        self.E_activation: float = None
101        """Activation energy or energy barrier, from the ground torsional state to the top of the potential barrier, `max(V) - min(eigenvalues)`"""
102        self.excitations: list = []
103        """Torsional excitations, as the difference between each energy level with respect to the ground state.
104
105        Considers the means between degenerated eigenvalues for all energy levels below `potential_max`.
106        """
107        self.splittings: list = []
108        """Tunnel splitting energies, for every degenerated energy level.
109        
110        Calculated for all `E_levels` as the difference between
111        the mean of the eigenvalues from A and the mean of the eigenvalues from E,
112        see [R. M. Dimeo, American Journal of Physics 71, 885–893 (2003)](https://doi.org/10.1119/1.1538575).
113        """
114        self.runtime: float = None
115        """Time taken to solve the eigenvalues."""

A new quantum system can be instantiated as system = qrotor.System(). This new system will contain the default values listed above.

version

Version of the package used to generate the data.

comment: str

Custom comment for the dataset.

searched_E: int

Number of energy eigenvalues to be searched.

correct_potential_offset: bool

Correct the potential offset as V - min(V) or not.

save_eigenvectors: bool

Save or not the eigenvectors. Final file size will be bigger.

tags: str

Custom tags separated by spaces, such as the molecular group, etc.

Can be used to filter between datasets.

B: float

Kinetic rotational energy, as in $B=\frac{\hbar^2}{2I}$.

Defaults to the value for a methyl group.

gridsize: int

Number of points in the grid.

grid

The grid with the points to be used in the calculation.

Can be set automatically over $2 \pi$ with System.set_grid(). Units must be in radians.

potential_name: str

Name of the desired potential: 'zero', 'titov2023', 'test'...

If empty or unrecognised, the custom potential values inside System.potential_values will be used.

potential_constants: list

List of constants to be used in the calculation of the potential energy, in the qrotor.potential module.

potential_values

Numpy ndarray with the potential values for each point in the grid.

Can be calculated with a function available in the qrotor.potential module, or loaded externally with the qrotor.potential.load() function. Potential energy units must be in meV.

potential_offset: float

min(V) before offset correction when correct_potential_offset = True

potential_min: float

min(V)

potential_max: float

max(V)

eigenvectors

Eigenvectors, if save_eigenvectors is True. Beware of the file size.

eigenvalues

Calculated eigenvalues of the system. In meV.

E_levels: list

List of eigenvalues grouped by energy levels, found below potential_max.

deg: float

Estimated degeneracy of the E_levels found below potential_max.

E_activation: float

Activation energy or energy barrier, from the ground torsional state to the top of the potential barrier, max(V) - min(eigenvalues)

excitations: list

Torsional excitations, as the difference between each energy level with respect to the ground state.

Considers the means between degenerated eigenvalues for all energy levels below potential_max.

splittings: list

Tunnel splitting energies, for every degenerated energy level.

Calculated for all E_levels as the difference between the mean of the eigenvalues from A and the mean of the eigenvalues from E, see R. M. Dimeo, American Journal of Physics 71, 885–893 (2003).

runtime: float

Time taken to solve the eigenvalues.

def solve(self, new_gridsize: int = None):
117    def solve(self, new_gridsize:int=None):
118        """Default user method to solve the quantum system.
119
120        The potential can be interpolated to a `new_gridsize`.
121
122        Same as running `qrotor.solve.energies(System)`
123        with an optional new gridsize.
124        """
125        from .solve import energies
126        if new_gridsize:
127            self.gridsize = new_gridsize
128        return energies(self)

Default user method to solve the quantum system.

The potential can be interpolated to a new_gridsize.

Same as running qrotor.solve.energies(System) with an optional new gridsize.

def solve_potential(self, new_gridsize: int = None):
130    def solve_potential(self, new_gridsize:int=None):
131        """Default user method to quickly solve the potential of the quantum system.
132
133        This method does not solve the energies of the system,
134        it just computes the potential and sets `System.potential_max`,
135        `System.potential_min` and `System.potential_offset` accordingly.
136        To solve the potential AND the energies, check `System.solve()`.
137
138        The potential can be interpolated to a `new_gridsize`.
139
140        Same as running `qrotor.solve.potential(System)`
141        with an optional new gridsize.
142        """
143        from .solve import potential
144        if new_gridsize:
145            self.gridsize = new_gridsize
146        return potential(self)

Default user method to quickly solve the potential of the quantum system.

This method does not solve the energies of the system, it just computes the potential and sets System.potential_max, System.potential_min and System.potential_offset accordingly. To solve the potential AND the energies, check System.solve().

The potential can be interpolated to a new_gridsize.

Same as running qrotor.solve.potential(System) with an optional new gridsize.

def change_phase(self, phase: float, calculate: bool = True):
148    def change_phase(self, phase:float, calculate:bool=True):
149        """Apply a phase shift to the grid and potential values.
150
151        The `phase` should be a multiple of $\\pi$ (e.g., 3/2 for $3\\pi/2$).
152        The resulting grid will be expressed between $-2\\pi$ and $2\\pi$.
153
154        The System is solved immediately after the phase change.
155        This last step ensures that all eigenvalues and wavefunctions are correct.
156        You can override this step with `calculate = False`,
157        but remember to solve the System later!
158        """
159        if not any(self.potential_values) or not any(self.grid):
160            raise ValueError("System.potential_values and System.grid must be set before applying a phase shift.")
161        # Normalise the phase between 0 and 2
162        if abs(phase) >= 2:
163            phase = phase % 2
164        while phase < 0:
165            phase = phase + 2
166        # Shift the grid, between -2pi and 2pi
167        self.grid = (self.grid + (phase * np.pi))
168        # Apply the phase shift to potential values
169        phase_points = int((phase / 2) * self.gridsize)
170        self.potential_values = np.roll(self.potential_values, phase_points)
171        # Check that the grid is still within -2pi and 2pi, otherwise normalise it for a final time
172        while self.grid[0] <= (-2 * np.pi + 0.1):  # With a small tolerance
173            self.grid = self.grid + 2 * np.pi
174        while self.grid[-1] >= 2.5 * np.pi:  # It was not a problem until reaching 5/2 pi
175            self.grid = self.grid -2 * np.pi
176        print(f'Potential shifted by {phase}π')
177        if calculate:
178            self.solve()
179        return self

Apply a phase shift to the grid and potential values.

The phase should be a multiple of $\pi$ (e.g., 3/2 for $3\pi/2$). The resulting grid will be expressed between $-2\pi$ and $2\pi$.

The System is solved immediately after the phase change. This last step ensures that all eigenvalues and wavefunctions are correct. You can override this step with calculate = False, but remember to solve the System later!

def set_grid(self, gridsize: int = None):
181    def set_grid(self, gridsize:int=None):
182        """Sets the `System.grid` to the specified `gridsize` from 0 to $2\\pi$.
183
184        If the system had a previous grid and potential values,
185        it will interpolate those values to the new gridsize,
186        using `qrotor.potential.interpolate()`.
187        """
188        if gridsize == self.gridsize:
189            return self  # Nothing to do here
190        if gridsize:
191            self.gridsize = gridsize
192        # Should we interpolate?
193        if any(self.potential_values) and any(self.grid) and self.gridsize:
194            from .potential import interpolate
195            self = interpolate(self)
196        # Should we create the values from zero?
197        elif self.gridsize:
198                self.grid = np.linspace(0, 2*np.pi, self.gridsize)
199        else:
200            raise ValueError('gridsize must be provided if there is no System.gridsize')
201        return self

Sets the System.grid to the specified gridsize from 0 to $2\pi$.

If the system had a previous grid and potential values, it will interpolate those values to the new gridsize, using qrotor.potential.interpolate().

def reduce_size(self):
203    def reduce_size(self):
204        """Discard data that takes too much space,
205        like eigenvectors, potential values and grids."""
206        self.eigenvectors = []
207        self.potential_values = []
208        self.grid = []
209        return self

Discard data that takes too much space, like eigenvectors, potential values and grids.

def summary(self):
211    def summary(self):
212        """Returns a dict with a summary of the System data."""
213        return {
214            'version': self.version,
215            'comment': self.comment,
216            'tags': self.tags,
217            'searched_E': self.searched_E,
218            'correct_potential_offset': self.correct_potential_offset,
219            'save_eigenvectors': self.save_eigenvectors,
220            'B': self.B,
221            'gridsize': self.gridsize,
222            'potential_name': self.potential_name,
223            'potential_constants': self.potential_constants.tolist() if isinstance(self.potential_constants, np.ndarray) else self.potential_constants,
224            'potential_offset': self.potential_offset,
225            'potential_min': self.potential_min,
226            'potential_max': self.potential_max,
227            'eigenvalues': self.eigenvalues.tolist() if isinstance(self.eigenvalues, np.ndarray) else self.eigenvalues,
228            'E_levels': self.E_levels,
229            'deg': self.deg,
230            'excitations': self.excitations,
231            'splittings': self.splittings,
232            'E_activation': self.E_activation,
233            'runtime': self.runtime,
234        }

Returns a dict with a summary of the System data.