X Tutup
Skip to content

Commit 68dc907

Browse files
committed
Last version with long URLs
1 parent f0b9dba commit 68dc907

File tree

1 file changed

+34
-22
lines changed

1 file changed

+34
-22
lines changed

book/book.tex

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
\newcommand{\thetitle}{Modeling and Simulation in Python}
1414
\newcommand{\thesubtitle}{}
1515
\newcommand{\theauthors}{Allen B. Downey}
16-
\newcommand{\theversion}{0.13.0}
16+
\newcommand{\theversion}{0.15.0}
1717

1818

1919
%%%% Both LATEX and PLASTEX
@@ -2798,7 +2798,7 @@ \section{Now with a TimeFrame}
27982798

27992799
If the number of state variables is small, storing them as separate \py{TimeSeries} objects might not be so bad. But a better alternative is to use a \py{TimeFrame}, which is another object are defined in the \py{modsim} library.
28002800

2801-
A \py{TimeFrame} is almost identical to a \py{DataFrame}, which we used in Section~\ref{worldpopdata}, with just a few changes I made to make them easier to use for our purposes. For more details, you can read the \py{modsim} library source code.
2801+
A \py{TimeFrame} is almost identical to a \py{DataFrame}, which we used in Section~\ref{worldpopdata}, with just a few changes I made to adapt it for our purposes. For more details, you can read the \py{modsim} library source code.
28022802

28032803
Here's a more concise version of \py{run_simulation} using a \py{TimeFrame}:
28042804

@@ -2813,13 +2813,13 @@ \section{Now with a TimeFrame}
28132813
system.results = frame
28142814
\end{python}
28152815

2816-
The first line creates an empty \py{TimeFrame} with one column for each state variables. Then, before the loop starts, we store the initial conditions in the \py{TimeFrame} at \py{t0}. Based on the way we've been using \py{TimeSeries} objects, it is tempting to write:
2816+
The first line creates an empty \py{TimeFrame} with one column for each state variable. Then, before the loop starts, we store the initial conditions in the \py{TimeFrame} at \py{t0}. Based on the way we've been using \py{TimeSeries} objects, it is tempting to write:
28172817

28182818
\begin{python}
28192819
frame[system.t0] = system.init
28202820
\end{python}
28212821

2822-
But when you use the bracket operator with a \py{TimeFrame} or \py{DataFrame}, it selects a column, not a row. For example, to select a column, we could write
2822+
But when you use the bracket operator with a \py{TimeFrame} or \py{DataFrame}, it selects a column, not a row. For example, to select a column, we could write:
28232823

28242824
\begin{python}
28252825
frame['S']
@@ -2854,7 +2854,7 @@ \section{Now with a TimeFrame}
28542854
\section{Metrics}
28552855
\label{metrics}
28562856

2857-
When we plot a time series, we get a view of everything that happened when the model ran, but often we want to boil it down to a few numbers, ideally one, that summarize the outcome. These summary statistics are called {\bf metrics}.
2857+
When we plot a time series, we get a view of everything that happened when the model ran, but often we want to boil it down to a few numbers that summarize the outcome. These summary statistics are called {\bf metrics}.
28582858

28592859
In the SIR model, we might want to know the time until the peak of the outbreak, the number of people who are sick at the peak, the number of students who will still be sick at the end of the semester, or the total number of students get sick at any point.
28602860

@@ -2891,7 +2891,7 @@ \section{Immunization}
28912891

28922892
Suppose there is a vaccine that causes a patient to become immune to the Freshman Plague without being infected. How might you modify the model to capture this effect?
28932893

2894-
One option is to treat immunization as a short cut from \py{S} to \py{R}, that is, from susceptible to removed (or resistant). We can implement this feature like this:
2894+
One option is to treat immunization as a short cut from \py{S} to \py{R}, that is, from susceptible to resistant\footnote{We can be flexible about what \py{R} stands for.}. We can implement this feature like this:
28952895

28962896
\begin{python}
28972897
def add_immunization(system, fraction):
@@ -3504,7 +3504,7 @@ \section{Newton's law of cooling}
35043504
%
35053505
\[ \frac{dT}{dt} = -r (T - T_{env}) \]
35063506
%
3507-
where $T$, the temperature of the object, is a function of time, $t$; $T_{env}$ is the temperature of the environment, and $r$ is a constant that characterizes how quickly heats moves across the boundary between the system and the environment.
3507+
where $T$, the temperature of the object, is a function of time, $t$; $T_{env}$ is the temperature of the environment, and $r$ is a constant that characterizes how quickly heats is transferred between the system and the environment.
35083508

35093509
Newton's so-called ``law" is really a model in the sense that it is approximately true in some conditions, only roughly true in others, and not at all true in others.
35103510

@@ -3805,7 +3805,7 @@ \section{Optimization}
38053805

38063806
\begin{figure}
38073807
\centerline{\includegraphics[height=3in]{figs/chap07-fig02.pdf}}
3808-
\caption{Final temperature as a function of when we add the milk.}
3808+
\caption{Final temperature as a function of the time the milk is added.}
38093809
\label{chap07-fig02}
38103810
\end{figure}
38113811

@@ -3962,11 +3962,11 @@ \section{The glucose minimal model}
39623962

39633963
\end{itemize}
39643964

3965-
The initial state of the model is $X(0) = I_b$ and $G(0) = G_0$, where $G_0$ is a constant that represents the concentration of blood sugar immediately after the injection. In theory we could estimate $G_0$ based on measurements, but in practice it takes time for the injected glucose to spread through the blood volume. Since $G_0$ is not measurable, it is treated as a {\bf free parameter} of the model, which means that we are free to chose it to fit the data.
3965+
The initial state of the model is $X(0) = I_b$ and $G(0) = G_0$, where $G_0$ is a constant that represents the concentration of blood sugar immediately after the injection. In theory we could estimate $G_0$ based on measurements, but in practice it takes time for the injected glucose to spread through the blood volume. Since $G_0$ is not measurable, it is treated as a {\bf free parameter} of the model, which means that we are free to choose it to fit the data.
39663966

39673967
\section{Data}
39683968

3969-
To develop and test the model, I'll use data from Pacini and Bergman\footnote{"MINMOD: a computer program to calculate insulin sensitivity and pancreatic responsivity from the frequently sampled intravenous glucose tolerance test", {\em Computer Methods and Programs in Biomedicine} 23: 113-122, 1986.}. The dataset is in a file in the repository for this book, which we can read into a \py{DataFrame}:
3969+
To develop and test the model, I'll use data from Pacini and Bergman\footnote{``MINMOD: A computer program to calculate insulin sensitivity and pancreatic responsivity from the frequently sampled intravenous glucose tolerance test", {\em Computer Methods and Programs in Biomedicine} 23: 113-122, 1986.}. The dataset is in a file in the repository for this book, which we can read into a \py{DataFrame}:
39703970

39713971
\begin{python}
39723972
data = pd.read_csv('glucose_insulin.csv', index_col='time')
@@ -4380,11 +4380,11 @@ \section{Newton's second law of motion}
43804380
%
43814381
\[ \frac{d^2y}{dx^2} = H(x, y, y') \]
43824382
%
4383-
where $H$ is another function and $y'$ is shorthand for $dy/dx$. In particular, we will work with one of the most famous, useful, and possibly the first second order ODE, Newton's second law of motion:
4383+
where $H$ is another function and $y'$ is shorthand for $dy/dx$. In particular, we will work with one of the most famous and useful second order ODEs, Newton's second law of motion:
43844384
%
43854385
\[ F = m a \]
43864386
%
4387-
where $F$ is a force or the total of a set of forces, $m$ is the mass of a moving object, and $a$ is acceleration.
4387+
where $F$ is a force or the total of a set of forces, $m$ is the mass of a moving object, and $a$ is its acceleration.
43884388

43894389
Newton's law might not look like a differential equation, until we realize that acceleration, $a$, is the second derivative of position, $y$, with respect to time, $t$. With the substitution
43904390
%
@@ -4408,14 +4408,14 @@ \section{Newton's second law of motion}
44084408

44094409
\end{itemize}
44104410

4411-
But for medium to large things with constant mass, moving at speeds that are medium to slow, Newton's model is a phenomenally useful. If we can quantify the forces that act on such an object, we can figure out how it will move.
4411+
But for medium to large things with constant mass, moving at speeds that are medium to slow, Newton's model is phenomenally useful. If we can quantify the forces that act on such an object, we can figure out how it will move.
44124412

44134413

44144414
\section{Dropping pennies}
44154415

44164416
As a first example, let's get back to the penny falling from the Empire State Building, which we considered in Section~\ref{penny}. We will implement two models of this system: first without air resistance, then with.
44174417

4418-
Given that the Empire State Building is \SI{381}{\meter} high, and assuming that the penny is dropped with 0 velocity, the initial conditions are:
4418+
Given that the Empire State Building is \SI{381}{\meter} high, and assuming that the penny is dropped with velocity zero, the initial conditions are:
44194419

44204420
\begin{python}
44214421
init = State(y=381 * m,
@@ -4448,7 +4448,7 @@ \section{Dropping pennies}
44484448

44494449
\py{ts} contains equally spaced points between \SI{0}{\second} and \SI{10}{\second}, including both endpoints.
44504450

4451-
Next we need a \py{System} object to contains the system parameters:
4451+
Next we need a \py{System} object to contain the system parameters:
44524452

44534453
\begin{python}
44544454
system = System(init=init, g=g, ts=ts)
@@ -4495,7 +4495,7 @@ \section{Dropping pennies}
44954495
slope_func(init, 0, system)
44964496
\end{python}
44974497

4498-
The result is a sequence containing \SI{0}{\meter\per\second} for velocity and \SI{-9.8}{\meter\per\second\squared} for acceleration. Now we can run \py{odeint} like this:
4498+
The result is a sequence containing \SI{0}{\meter\per\second} for velocity and \SI{9.8}{\meter\per\second\squared} for acceleration. Now we can run \py{odeint} like this:
44994499

45004500
\begin{python}
45014501
run_odeint(system, slope_func)
@@ -4607,9 +4607,9 @@ \section{With air resistance}
46074607
\section{Implementation}
46084608
\label{condition}
46094609

4610-
As the number of system parameters increases, and as we need to do more work to compute them, we will find it useful to define a \py{Condition} object to contain the quantities we need to make a \py{System} object.
4610+
As the number of system parameters increases, and as we need to do more work to compute them, we will find it useful to define a \py{Condition} object to contain the quantities we need to make a \py{System} object. \py{Condition} objects are similar to \py{System} and \py{State} objects; in fact, all three have the same capabilities. I have given them different names to document the different roles they play.
46114611

4612-
The way we create a \py{Condition} object is the same as for \py{System} and \py{State} objects. In fact, these three object types have the same capabilities; I have given them different names just to identify their different roles. Here's the \py{Condition} object for the falling penny:
4612+
Here's the \py{Condition} object for the falling penny:
46134613

46144614
\begin{python}
46154615
condition = Condition(height = 381 * m,
@@ -5068,11 +5068,23 @@ \section{Finding the range}
50685068

50695069
\py{interpolate_range} uses \py{idxmax} to find the time when the ball hits its peak (see Section~\ref{metrics}).
50705070

5071-
Then it uses \py{loc} to extract only the points after \py{t_peak}. The index here is a {\bf slice}. In general, you can use a slice to select a range of values from a \py{Series}, specifying the start and end indices. In this example we only specify the beginning, so we get everything from \py{t_peak} the end of the \py{Series}.
5071+
Then it uses \py{ys.loc} to extract only the points from \py{t_peak} to the end. The index in brackets includes a colon (\py{:}), which indicates that it is a {\bf slice index}. In general, a slice selects a range of elements from a \py{Series}, specifying the start and end indices. For example, the following slice selects elements from \py{t_peak} to \py{t_land}, including both:
5072+
5073+
\begin{python}
5074+
ys.loc[t_peak:t_land]
5075+
\end{python}
5076+
5077+
If we omit the first index, like this:
5078+
5079+
\begin{python}
5080+
ys.loc[:t_land]
5081+
\end{python}
5082+
5083+
we get everything from the beginning to \py{t_land}. If we omit the second index, as in \py{interpolate_range}, we get everything from \py{t_peak} to the end of the \py{Series}. For more about indexing with \py{loc}, see \url{https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.loc.html}.
50725084

50735085
Next it uses \py{interp_inverse}, which we saw in Section~\ref{sidewalk}, to make \py{T}, which is an interpolation function that maps from height to time. So \py{t_land} is the time when height is 0.
50745086

5075-
Finally, it uses \py{interpolate} to make \py{X}, which is an interpolation function that maps from time to $x$ component. So \py{X(T_land)} is the distance from home plate when the ball lands.
5087+
Finally, it uses \py{interpolate} to make \py{X}, which is an interpolation function that maps from time to $x$ component. So \py{X(t_land)} is the distance from home plate when the ball lands.
50765088

50775089
We can call \py{interpolate_range} like this:
50785090

@@ -5158,7 +5170,7 @@ \chapter{Rotation}
51585170

51595171
If the configuration of an object changes over time, it might become easier or harder to spin, which explains the surprising dynamics of gymnasts, divers, ice skaters, etc.
51605172

5161-
And when you applying a twisting force to a rotating object, the effect is often contrary to intuition. For an example, see this video on gyroscopic precession \url{https://www.youtube.com/watch?v=ty9QSiVC2g0}.
5173+
And when you apply a twisting force to a rotating object, the effect is often contrary to intuition. For an example, see this video on gyroscopic precession \url{https://www.youtube.com/watch?v=ty9QSiVC2g0}.
51625174

51635175
In this chapter, we will not take on the physics of rotation in all its glory. Rather, we will focus on simple scenarios where all rotation and all twisting forces are around a single axis. In that case, we can treat some vector quantities as if they were scalars (in the same way that we sometimes treat velocity as a scalar with an implicit direction).
51645176

@@ -5421,7 +5433,7 @@ \section{Moment of inertia}
54215433
%
54225434
Where $\alpha$ is angular acceleration and $I$ is {\bf moment of inertia}. Just as mass is what makes it harder to accelerate an object\footnote{That might sound like a dumb way to describe mass, but its actually one of the fundamental definitions.}, moment of inertia is what makes it harder to spin an object.
54235435

5424-
In the most general case, a 3D object rotating around an arbitrary axis, moment of inertia is a tensor quantity, which is like a function that takes a vector as a parameter and returns a vector as a result.
5436+
In the most general case, a 3-D object rotating around an arbitrary axis, moment of inertia is a tensor, which is a function that takes a vector as a parameter and returns a vector as a result.
54255437

54265438
Fortunately, in a system where all rotation and torque happens around a single axis, we don't have to deal with the most general case. We can treat moment of inertia as a scalar quantity.
54275439

0 commit comments

Comments
 (0)
X Tutup