Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor code #21

Merged
merged 10 commits into from
Oct 20, 2023
108 changes: 97 additions & 11 deletions double_pendula/double_pendula.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
"""Model of a double pendulum"""
# Author: Chris Greening
# Date: 2019-07-15

from typing import Tuple, List

Expand Down Expand Up @@ -51,35 +49,123 @@ def __init__(self, L1: int = 1, L2: int = 1, m1: int = 1, m2: int = 1,
self.max_length = self.pendulum1.L + self.pendulum2.L

def get_frame_x(self, i: int) -> Tuple[int]:
"""Return x coordinates of the system of a specific index"""
"""Return x coordinates of the system of a specific index.

Parameters
----------
i : int
The index of the frame for which to return x coordinates.

Returns
-------
Tuple[int]
A tuple containing the x coordinates of the system at the specified index.
The first element is always 0, followed by the x coordinate of `pendulum1` and
the x coordinate of `pendulum2`.
"""
return (0, self.pendulum1.x[i], self.pendulum2.x[i])

def get_frame_y(self, i: int) -> Tuple[int]:
"""Return y coordinates of the system of a specific index"""
"""
Return y coordinates of the system of a specific index.

Parameters
----------
i : int
The index of the frame for which to return y coordinates.

Returns
-------
Tuple[int]
A tuple containing the y coordinates of the system at the specified index.
The first element is always 0, followed by the y coordinate of `pendulum1` and
the y coordinate of `pendulum2`.
"""
return (0, self.pendulum1.y[i],self.pendulum2.y[i])

def get_frame_coordinates(self, i: int) -> Tuple[Tuple[int]]:
"""Return the x,y coordinates at a given frame"""
"""Return the x,y coordinates at a given frame.

Parameters
----------
i : int
The index of the frame for which to return x,y coordinates.

Returns
-------
Tuple[Tuple[int]]
A tuple containing two tuples: the first one is the x coordinates
and the second one is the y coordinates of the system at the specified
index. Each inner tuple follows the format:
(coordinate of origin, coordinate of `pendulum1`, coordinate of `pendulum2`).
"""
return (self.get_frame_x(i), self.get_frame_y(i))

def get_max_x(self) -> float:
"""Return the maximum x-coord of the double pendulum"""
"""
Return the maximum x-coordinate of the double pendulum.

Returns
-------
float
The maximum x-coordinate that the double pendulum reaches.
"""
return self.pendulum2.get_max_x()

def get_max_y(self) -> float:
"""Return the maximum y-coord of the double pendulum"""
"""
Return the maximum y-coordinate of the double pendulum.

Returns
-------
float
The maximum y-coordinate that the double pendulum reaches.
"""
return self.pendulum2.get_max_y()

def get_max_coordinates(self) -> float:
"""Return the maximum coordinates the overall system reaches"""
"""
Return the maximum coordinates the overall system reaches.

Returns
-------
float
The maximum distance from the origin that the overall double pendulum system reaches.
"""
return self.pendulum2.get_max_coordinates()

@classmethod
def create_multiple_double_pendula(
cls, num_pendula: int = 1, L1: float = 1.0,
L2: float = 1.0, m1: float = 1.0, m2: float = 1.0,
initial_theta: float = 90, dtheta: float = .05) -> List["DoublePendulum"]:
"""Returns a list of DoublePendulum's each offset slightly from each other"""
initial_theta: float = 90, dtheta: float = .05) -> List["DoublePendula"]:
"""
Creates and returns a list of DoublePendula objects with initial
conditions offset by dtheta.

Parameters
----------
num_pendula : int, optional
Number of DoublePendula objects to create, default is 1.
L1 : float, optional
Length of the first pendulum arm, default is 1.0.
L2 : float, optional
Length of the second pendulum arm, default is 1.0.
m1 : float, optional
Mass of the first pendulum bob, default is 1.0.
m2 : float, optional
Mass of the second pendulum bob, default is 1.0.
initial_theta : float, optional
Initial angle in degrees of the first pendulum, default is 90.
dtheta : float, optional
Offset in initial angle in degrees for each subsequent pendulum,
default is 0.05.

Returns
-------
List["DoublePendula"]
A list containing the created DoublePendula objects.
"""
# pylint: disable=too-many-arguments
pendula = []
created_pendula = 0
Expand Down Expand Up @@ -129,4 +215,4 @@ def _calculate_system(self) -> None:

def __repr__(self):
# pylint: disable=line-too-long
return f"< DoublePendulum: L1={self.pendulum1.L} m1={self.pendulum1.m} L2={self.pendulum2.L} m2={self.pendulum2.m} y0={self.y0} >"
return f"< DoublePendula: L1={self.pendulum1.L} m1={self.pendulum1.m} L2={self.pendulum2.L} m2={self.pendulum2.m} y0={self.y0} >"
2 changes: 0 additions & 2 deletions double_pendula/equations.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
"""Module for storing equations relevant to calculating the double pendulum's movement"""
# Author: Chris Greening
# Date: 2022-10-29

import numpy as np
import scipy.integrate
Expand Down
37 changes: 30 additions & 7 deletions double_pendula/pendulum.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
"""Model of a single pendulum"""
# Author: Chris Greening
# Date: 2022-10-29

from typing import Tuple

Expand Down Expand Up @@ -46,17 +44,42 @@ def calculate_path(self, theta: float, dtheta: float, x0: float = 0, y0: float =
self.dtheta = dtheta
self.x = self.L*np.sin(self.theta) + x0
self.y = self.L*np.cos(self.theta) + y0
self.df = pd.DataFrame({"theta": self.theta, "dtheta": self.dtheta,
"x": self.x, "y": self.y})
self.df = pd.DataFrame({
"theta": self.theta,
"dtheta": self.dtheta,
"x": self.x,
"y": self.y
})

def get_max_x(self) -> float:
"""Return the maximum x-value that this pendulum reaches"""
"""
Return the maximum x-coordinate of the pendulum.

Returns
-------
float
The maximum x-coordinate that the pendulum reaches.
"""
return max(self.x)

def get_max_y(self) -> float:
"""Return the maximum y-value that this pendulum reaches"""
"""
Return the maximum y-coordinate of the double pendulum.

Returns
-------
float
The maximum y-coordinate that the double pendulum reaches.
"""
return max(self.y)

def get_max_coordinates(self) -> Tuple[float, float]:
"""Return maximum cartesian coordinate that this system reaches"""
"""
Return the maximum coordinates the overall system reaches.

Returns
-------
float
The maximum distance from the origin that the overall double pendulum system reaches.
"""
return (self.get_max_x(), self.get_max_y())
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

setuptools.setup(
name="double-pendula",
version="0.1.4",
version="0.1.5",
author="Chris Greening",
author_email="chris@christophergreening.com",
description="Library for animating double pendula in Python",
Expand Down