Skip to content

Commit

Permalink
Merge pull request #21 from chris-greening/refactor-code
Browse files Browse the repository at this point in the history
Refactor code
  • Loading branch information
chris-greening authored Oct 20, 2023
2 parents d3f3e68 + 263af22 commit b7b034f
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 21 deletions.
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

0 comments on commit b7b034f

Please sign in to comment.