Skip to content

Nosé-Hoover oscillator

The Nosé-Hoover oscillator x' = y, y' = y z - x, z' = 1 - y², with tori next to a chaotic sea.

  • Name: nose_hoover
  • Field: mathematics/dynamical_systems
  • Formalism: ordinary differential equations
  • References: Hoover 1995; Datseris and Parlitz 2022

Select this system

from skcomplex.systems import create_simulation, create_system, describe

system = create_system('nose_hoover')
entry = describe('nose_hoover')
trajectory = create_simulation('nose_hoover').prepare().run().trajectory_

Factory

@register_system(
    field='mathematics/dynamical_systems',
    tags=('chaos', 'ode', 'conservative', 'thermostat', 'kam'),
    references=('Hoover 1995', 'Datseris and Parlitz 2022'),
    defaults={'until': 200.0, 'dt': 0.05},
)
def nose_hoover(x: float = 0.0, y: float = 0.1, z: float = 0.0) -> System:
    """Return the Nosé-Hoover oscillator `x' = y`, `y' = y z - x`, `z' = 1 - y²`, with tori next to a chaotic sea.

    The flow conserves volume on average and its state space is mixed. From `(0, 1.549934227822898, 0)` the orbit is
    periodic, from `(0, 1, 0)` it winds on a torus around that orbit, and from the default `(0, 0.1, 0)` it is chaotic
    (Datseris and Parlitz 2022, Exercise 2.11). Since `z' = 1 - y²`, every bounded orbit has `<y²> = 1`.

    Args:
        x:
            The initial position.

        y:
            The initial momentum.

        z:
            The initial friction of the thermostat.

    Returns:
        system:
            The system, with the states `oscillator.x`, `oscillator.y`, and `oscillator.z`.

    Examples:
        >>> from skcomplex.systems.mathematics.dynamical_systems import nose_hoover
        >>> nose_hoover(y=1.0).elements[0].y
        1.0
    """
    return System(elements=[NoseHooverElement('oscillator', x=x, y=y, z=z)])

Components

Elements:

  • NoseHooverElement, from Element
class NoseHooverElement(Element):
    """Nosé-Hoover oscillator `x' = y`, `y' = y z - x`, `z' = 1 - y²`, a conservative flow with tori and chaos.

    Args:
        label:
            The label of the element.

        visual:
            How the element is drawn, or `None` for `default_visual_`.

        x:
            The initial position.

        y:
            The initial momentum.

        z:
            The initial friction of the thermostat.

    Examples:
        >>> from skcomplex.systems.mathematics.dynamical_systems import NoseHooverElement
        >>> NoseHooverElement('oscillator', y=1.0).y
        1.0
    """

    def __init__(
        self,
        label: str,
        visual: VisualSpec | None = None,
        *,
        x: Annotated[object, StateSpec()] = 0.0,
        y: Annotated[object, StateSpec()] = 0.1,
        z: Annotated[object, StateSpec()] = 0.0,
    ) -> None:
        super().__init__(label, visual=visual)
        self.x = x
        self.y = y
        self.z = z

    def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
        """Return the rates of the position, the momentum, and the friction.

        Args:
            s:
                The namespace of the symbols the laws can use.

        Returns:
            laws:
                The laws of the element.
        """
        return [RateLaw(s.x, s.y), RateLaw(s.y, s.y * s.z - s.x), RateLaw(s.z, 1 - s.y**2)]

Equations

oscillator.x: diff(x_oscillator(t), t) == y_oscillator(t)
oscillator.y: diff(y_oscillator(t), t) == y_oscillator(t)*z_oscillator(t) - x_oscillator(t)
oscillator.z: diff(z_oscillator(t), t) == -y_oscillator(t)^2 + 1