<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Simulating a Yo-Yo
Modeling and Simulation in Python
Copyright 2021 Allen Downey
License
Step1:  Yo-yo
Suppose you are holding a yo-yo with a length of string wound around its axle, and you drop it while holding the end of the string stationary. As gravity accelerates the yo-yo downward, tension in the string exerts a force upward. Since this force acts on a point offset from the center of mass, it exerts a torque that causes the yo-yo to spin.
The following diagram shows the forces on the yo-yo and the resulting torque. The outer shaded area shows the body of the yo-yo. The inner shaded area shows the rolled up string, the radius of which changes as the yo-yo unrolls.
In this system, we can't figure out the linear and angular acceleration independently; we have to solve a system of equations
Step2:  The results are
$T      = m g I / I^*   $
$a      = -m g r^2 / I^* $
$\alpha = m g r / I^*    $
where $I^*$ is the augmented moment of inertia, $I + m r^2$.
You can also see the derivation of these equations in this video.
We can use these equations for $a$ and $\alpha$ to write a slope function and simulate this system.
Exercise
Step3:  Rmin is the radius of the axle.  Rmax is the radius of the axle plus rolled string.
Rout is the radius of the yo-yo body.  mass is the total mass of the yo-yo, ignoring the string.  
L is the length of the string.
g is the acceleration of gravity.
Step4:  Based on these parameters, we can compute the moment of inertia for the yo-yo, modeling it as a solid cylinder with uniform density (see here).
In reality, the distribution of weight in a yo-yo is often designed to achieve desired effects.  But we'll keep it simple.
Step5:  And we can compute k, which is the constant that determines how the radius of the spooled string decreases as it unwinds.
Step6:  The state variables we'll use are angle, theta, angular velocity, omega, the length of the spooled string, y, and the linear velocity of the yo-yo, v.
Here is a State object with the the initial conditions.
Step7:  And here's a System object with init and t_end (chosen to be longer than I expect for the yo-yo to drop 1 m).
Step8:  Write a slope function for this system, using these results from the book
Step9:  Test your slope function with the initial conditions.
The results should be approximately
0, 180.5, 0, -2.9
Step10:  Notice that the initial acceleration is substantially smaller than g because the yo-yo has to start spinning before it can fall.
Write an event function that will stop the simulation when y is 0.
Step11:  Test your event function
Step12:  Then run the simulation.
Step13:  Check the final state.  If things have gone according to plan, the final value of y should be close to 0.
Step14:  How long does it take for the yo-yo to fall 1 m?  Does the answer seem reasonable?
The following cells plot the results.
theta should increase and accelerate.
Step15:  y should decrease and accelerate down.
Step16:  Plot velocity as a function of time; is the acceleration constant?
Step17:  We can use gradient to estimate the derivative of v.  How does the acceleration of the yo-yo compare to g?
Step18:  And we can use the formula for r to plot the radius of the spooled thread over time.
<ASSISTANT_TASK:>
Python Code:
# install Pint if necessary
try:
    import pint
except ImportError:
    !pip install pint
# download modsim.py if necessary
from os.path import exists
filename = 'modsim.py'
if not exists(filename):
    from urllib.request import urlretrieve
    url = 'https://raw.githubusercontent.com/AllenDowney/ModSim/main/'
    local, _ = urlretrieve(url+filename, filename)
    print('Downloaded ' + local)
# import functions from modsim
from modsim import *
Explanation: Simulating a Yo-Yo
Modeling and Simulation in Python
Copyright 2021 Allen Downey
License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
End of explanation
from sympy import symbols, Eq, solve
T, a, alpha, I, m, g, r = symbols('T a alpha I m g r')
eq1 = Eq(a, -r * alpha)
eq1
eq2 = Eq(T - m * g, m * a)
eq2
eq3 = Eq(T * r, I * alpha)
eq3
soln = solve([eq1, eq2, eq3], [T, a, alpha])
soln[T]
soln[a]
soln[alpha]
Explanation: Yo-yo
Suppose you are holding a yo-yo with a length of string wound around its axle, and you drop it while holding the end of the string stationary. As gravity accelerates the yo-yo downward, tension in the string exerts a force upward. Since this force acts on a point offset from the center of mass, it exerts a torque that causes the yo-yo to spin.
The following diagram shows the forces on the yo-yo and the resulting torque. The outer shaded area shows the body of the yo-yo. The inner shaded area shows the rolled up string, the radius of which changes as the yo-yo unrolls.
In this system, we can't figure out the linear and angular acceleration independently; we have to solve a system of equations:
$\sum F = m a $
$\sum \tau = I \alpha$
where the summations indicate that we are adding up forces and torques.
As in the previous examples, linear and angular velocity are related because of the way the string unrolls:
$\frac{dy}{dt} = -r \frac{d \theta}{dt} $
In this example, the linear and angular accelerations have opposite sign.  As the yo-yo rotates counter-clockwise, $\theta$ increases and $y$, which is the length of the rolled part of the string, decreases.
Taking the derivative of both sides yields a similar relationship between linear and angular acceleration:
$\frac{d^2 y}{dt^2} = -r \frac{d^2 \theta}{dt^2} $
Which we can write more concisely:
$ a = -r \alpha $
This relationship is not a general law of nature; it is specific to scenarios like this where there is rolling without stretching or slipping.
Because of the way we've set up the problem, $y$ actually has two meanings: it represents the length of the rolled string and the height of the yo-yo, which decreases as the yo-yo falls.  Similarly, $a$ represents acceleration in the length of the rolled string and the height of the yo-yo.
We can compute the acceleration of the yo-yo by adding up the linear forces:
$\sum F = T - mg = ma $
Where $T$ is positive because the tension force points up, and $mg$ is negative because gravity points down.
Because gravity acts on the center of mass, it creates no torque, so the only torque is due to tension:
$\sum \tau = T r = I \alpha $
Positive (upward) tension yields positive (counter-clockwise) angular acceleration.
Now we have three equations in three unknowns, $T$, $a$, and $\alpha$, with $I$, $m$, $g$, and $r$ as known parameters.  We could solve these equations by hand, but we can also get SymPy to do it for us.
End of explanation
Rmin = 8e-3     # m
Rmax = 16e-3    # m
Rout = 35e-3    # m
mass = 50e-3    # kg
L = 1           # m
g = 9.8         # m / s**2
Explanation: The results are
$T      = m g I / I^*   $
$a      = -m g r^2 / I^* $
$\alpha = m g r / I^*    $
where $I^*$ is the augmented moment of inertia, $I + m r^2$.
You can also see the derivation of these equations in this video.
We can use these equations for $a$ and $\alpha$ to write a slope function and simulate this system.
Exercise:  Simulate the descent of a yo-yo.  How long does it take to reach the end of the string?
Here are the system parameters:
End of explanation
1 / (Rmax)
Explanation: Rmin is the radius of the axle.  Rmax is the radius of the axle plus rolled string.
Rout is the radius of the yo-yo body.  mass is the total mass of the yo-yo, ignoring the string.  
L is the length of the string.
g is the acceleration of gravity.
End of explanation
I = mass * Rout**2 / 2
I
Explanation: Based on these parameters, we can compute the moment of inertia for the yo-yo, modeling it as a solid cylinder with uniform density (see here).
In reality, the distribution of weight in a yo-yo is often designed to achieve desired effects.  But we'll keep it simple.
End of explanation
k = (Rmax**2 - Rmin**2) / 2 / L   
k
Explanation: And we can compute k, which is the constant that determines how the radius of the spooled string decreases as it unwinds.
End of explanation
init = State(theta=0, omega=0, y=L, v=0)
Explanation: The state variables we'll use are angle, theta, angular velocity, omega, the length of the spooled string, y, and the linear velocity of the yo-yo, v.
Here is a State object with the the initial conditions.
End of explanation
system = System(init=init, t_end=2)
Explanation: And here's a System object with init and t_end (chosen to be longer than I expect for the yo-yo to drop 1 m).
End of explanation
# Solution
def slope_func(t, state, system):
    theta, omega, y, v = state
    
    r = np.sqrt(2*k*y + Rmin**2)
    alpha = mass * g * r / (I + mass * r**2)
    a = -r * alpha
        
    return omega, alpha, v, a        
Explanation: Write a slope function for this system, using these results from the book:
$ r = \sqrt{2 k y + R_{min}^2} $ 
$ T      = m g I / I^*  $
$ a      = -m g r^2 / I^* $
$ \alpha  = m g r / I^*  $
where $I^*$ is the augmented moment of inertia, $I + m r^2$.
End of explanation
# Solution
slope_func(0, system.init, system)
Explanation: Test your slope function with the initial conditions.
The results should be approximately
0, 180.5, 0, -2.9
End of explanation
# Solution
def event_func(t, state, system):
    theta, omega, y, v = state
    return y
Explanation: Notice that the initial acceleration is substantially smaller than g because the yo-yo has to start spinning before it can fall.
Write an event function that will stop the simulation when y is 0.
End of explanation
# Solution
event_func(0, system.init, system)
Explanation: Test your event function:
End of explanation
# Solution
results, details = run_solve_ivp(system, slope_func, 
                                 events=event_func, max_step=0.05)
details.message
Explanation: Then run the simulation.
End of explanation
# Solution
results.tail()
Explanation: Check the final state.  If things have gone according to plan, the final value of y should be close to 0.
End of explanation
results.theta.plot(color='C0', label='theta')
decorate(xlabel='Time (s)',
         ylabel='Angle (rad)')
Explanation: How long does it take for the yo-yo to fall 1 m?  Does the answer seem reasonable?
The following cells plot the results.
theta should increase and accelerate.
End of explanation
results.y.plot(color='C1', label='y')
decorate(xlabel='Time (s)',
         ylabel='Length (m)')
    
Explanation: y should decrease and accelerate down.
End of explanation
results.v.plot(label='velocity', color='C3')
decorate(xlabel='Time (s)',
         ylabel='Velocity (m/s)')
Explanation: Plot velocity as a function of time; is the acceleration constant?
End of explanation
a = gradient(results.v)
a.plot(label='acceleration', color='C4')
decorate(xlabel='Time (s)',
         ylabel='Acceleration (m/$s^2$)')
Explanation: We can use gradient to estimate the derivative of v.  How does the acceleration of the yo-yo compare to g?
End of explanation
r = np.sqrt(2*k*results.y + Rmin**2)
r.plot(label='radius')
decorate(xlabel='Time (s)',
         ylabel='Radius of spooled thread (m)')
import pandas as pd
s = pd.date_range('2020-1', '2020-12', freq='M').to_series()
list(s.dt.month_name())
pd.interval_range(start=pd.Timestamp('2017-01-01'),
                  periods=3, freq='MS').dt
Explanation: And we can use the formula for r to plot the radius of the spooled thread over time.
End of explanation
<END_TASK>