mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Discrete case scenes for diffyq part 3
This commit is contained in:
parent
4196bb627e
commit
6f7e123b1a
5 changed files with 359 additions and 5 deletions
|
@ -32,6 +32,13 @@ SCENES_IN_ORDER = [
|
||||||
StraightLine3DGraph,
|
StraightLine3DGraph,
|
||||||
SimulateLinearGraph,
|
SimulateLinearGraph,
|
||||||
EmphasizeBoundaryPoints,
|
EmphasizeBoundaryPoints,
|
||||||
|
ShowNewRuleAtDiscreteBoundary,
|
||||||
|
DiscreteEvolutionPoint25,
|
||||||
|
DiscreteEvolutionPoint1,
|
||||||
|
FlatEdgesForDiscreteEvolution,
|
||||||
|
FlatEdgesForDiscreteEvolutionTinySteps,
|
||||||
|
FlatEdgesContinuousEvolution,
|
||||||
|
FlatAtBoundaryWords,
|
||||||
|
|
||||||
# SimpleCosExpGraph,
|
# SimpleCosExpGraph,
|
||||||
# AddMultipleSolutions,
|
# AddMultipleSolutions,
|
||||||
|
|
|
@ -349,7 +349,7 @@ class BringTwoRodsTogether(Scene):
|
||||||
if (0 < i < len(points) - 1):
|
if (0 < i < len(points) - 1):
|
||||||
second_deriv = d2y / (dx**2)
|
second_deriv = d2y / (dx**2)
|
||||||
else:
|
else:
|
||||||
second_deriv = d2y / dx
|
second_deriv = 2 * d2y / (dx**2)
|
||||||
# second_deriv = 0
|
# second_deriv = 0
|
||||||
|
|
||||||
y_change[i] = alpha * second_deriv * dt / n_mini_steps
|
y_change[i] = alpha * second_deriv * dt / n_mini_steps
|
||||||
|
|
|
@ -2,6 +2,301 @@ from manimlib.imports import *
|
||||||
from active_projects.ode.part2.heat_equation import *
|
from active_projects.ode.part2.heat_equation import *
|
||||||
|
|
||||||
|
|
||||||
class NewSceneName(Scene):
|
class ShowNewRuleAtDiscreteBoundary(DiscreteSetup):
|
||||||
|
CONFIG = {
|
||||||
|
"axes_config": {
|
||||||
|
"x_min": 0,
|
||||||
|
"stroke_width": 1,
|
||||||
|
"x_axis_config": {
|
||||||
|
"include_tip": False,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"freq_amplitude_pairs": [
|
||||||
|
(1, 0.5),
|
||||||
|
(2, 1),
|
||||||
|
(3, 0.5),
|
||||||
|
(4, 0.3),
|
||||||
|
],
|
||||||
|
"v_line_config": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"step_size": 1,
|
||||||
|
"wait_time": 15,
|
||||||
|
"alpha": 0.25,
|
||||||
|
}
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
pass
|
self.add_axes()
|
||||||
|
self.set_points()
|
||||||
|
self.show_boundary_point_influenced_by_neighbor()
|
||||||
|
self.add_clock()
|
||||||
|
self.let_evolve()
|
||||||
|
|
||||||
|
def set_points(self):
|
||||||
|
axes = self.axes
|
||||||
|
for mob in axes.family_members_with_points():
|
||||||
|
if isinstance(mob, Line):
|
||||||
|
mob.set_stroke(width=1)
|
||||||
|
|
||||||
|
step_size = self.step_size
|
||||||
|
xs = np.arange(
|
||||||
|
axes.x_min,
|
||||||
|
axes.x_max + step_size,
|
||||||
|
step_size
|
||||||
|
)
|
||||||
|
|
||||||
|
dots = self.dots = self.get_dots(axes, xs)
|
||||||
|
self.v_lines = self.get_v_lines(dots)
|
||||||
|
self.rod_pieces = self.get_rod_pieces(dots)
|
||||||
|
|
||||||
|
# rod_pieces
|
||||||
|
|
||||||
|
self.add(self.dots)
|
||||||
|
self.add(self.v_lines)
|
||||||
|
self.add(self.rod_pieces)
|
||||||
|
|
||||||
|
def show_boundary_point_influenced_by_neighbor(self):
|
||||||
|
dots = self.dots
|
||||||
|
ld = dots[0]
|
||||||
|
ld_in = dots[1]
|
||||||
|
rd = dots[-1]
|
||||||
|
rd_in = dots[-2]
|
||||||
|
v_len = 0.75
|
||||||
|
l_arrow = Vector(v_len * LEFT)
|
||||||
|
l_arrow.move_to(ld.get_left(), RIGHT)
|
||||||
|
r_arrow = Vector(v_len * RIGHT)
|
||||||
|
r_arrow.move_to(rd.get_right(), LEFT)
|
||||||
|
arrows = VGroup(l_arrow, r_arrow)
|
||||||
|
q_marks = VGroup(*[
|
||||||
|
TexMobject("?").scale(1.5).next_to(
|
||||||
|
arrow, arrow.get_vector()
|
||||||
|
)
|
||||||
|
for arrow in arrows
|
||||||
|
])
|
||||||
|
|
||||||
|
arrows.set_color(YELLOW)
|
||||||
|
q_marks.set_color(YELLOW)
|
||||||
|
|
||||||
|
blocking_rects = VGroup(*[
|
||||||
|
BackgroundRectangle(VGroup(
|
||||||
|
*dots[i:-i],
|
||||||
|
*self.rod_pieces[i:-i]
|
||||||
|
))
|
||||||
|
for i in [1, 2]
|
||||||
|
])
|
||||||
|
for rect in blocking_rects:
|
||||||
|
rect.stretch(1.1, dim=1, about_edge=UP)
|
||||||
|
|
||||||
|
self.play(FadeIn(blocking_rects[0]))
|
||||||
|
self.play(
|
||||||
|
LaggedStartMap(ShowCreation, arrows),
|
||||||
|
LaggedStart(*[
|
||||||
|
FadeInFrom(q_mark, -arrow.get_vector())
|
||||||
|
for q_mark, arrow in zip(q_marks, arrows)
|
||||||
|
]),
|
||||||
|
run_time=1.5
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
# Point to inward neighbord
|
||||||
|
new_arrows = VGroup(*[
|
||||||
|
Arrow(
|
||||||
|
d1.get_center(),
|
||||||
|
VGroup(d1, d2).get_center(),
|
||||||
|
buff=0,
|
||||||
|
).match_style(l_arrow)
|
||||||
|
for d1, d2 in [(ld, ld_in), (rd, rd_in)]
|
||||||
|
])
|
||||||
|
new_arrows.match_style(arrows)
|
||||||
|
|
||||||
|
l_brace = Brace(VGroup(ld, ld_in), DOWN)
|
||||||
|
r_brace = Brace(VGroup(rd, rd_in), DOWN)
|
||||||
|
braces = VGroup(l_brace, r_brace)
|
||||||
|
for brace in braces:
|
||||||
|
brace.align_to(
|
||||||
|
self.axes.x_axis.get_center(), UP
|
||||||
|
)
|
||||||
|
brace.shift(SMALL_BUFF * DOWN)
|
||||||
|
brace.add(brace.get_tex("\\Delta x"))
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
ReplacementTransform(arrows, new_arrows),
|
||||||
|
FadeOut(q_marks),
|
||||||
|
ReplacementTransform(*blocking_rects)
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(FadeInFrom(braces, UP))
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
FadeOut(new_arrows),
|
||||||
|
FadeOut(blocking_rects[1]),
|
||||||
|
FadeOut(braces),
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_clock(self):
|
||||||
|
super().add_clock()
|
||||||
|
self.time_label.add_updater(
|
||||||
|
lambda d, dt: d.increment_value(dt)
|
||||||
|
)
|
||||||
|
VGroup(
|
||||||
|
self.clock,
|
||||||
|
self.time_label
|
||||||
|
).shift(2 * LEFT)
|
||||||
|
|
||||||
|
def let_evolve(self):
|
||||||
|
dots = self.dots
|
||||||
|
dots.add_updater(self.update_dots)
|
||||||
|
|
||||||
|
wait_time = self.wait_time
|
||||||
|
self.play(
|
||||||
|
ClockPassesTime(
|
||||||
|
self.clock,
|
||||||
|
run_time=wait_time,
|
||||||
|
hours_passed=wait_time,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
def get_dots(self, axes, xs):
|
||||||
|
dots = VGroup(*[
|
||||||
|
Dot(axes.c2p(x, self.temp_func(x, 0)))
|
||||||
|
for x in xs
|
||||||
|
])
|
||||||
|
|
||||||
|
max_width = 0.8 * self.step_size
|
||||||
|
for dot in dots:
|
||||||
|
dot.add_updater(self.update_dot_color)
|
||||||
|
if dot.get_width() > max_width:
|
||||||
|
dot.set_width(max_width)
|
||||||
|
|
||||||
|
return dots
|
||||||
|
|
||||||
|
def get_v_lines(self, dots):
|
||||||
|
return always_redraw(lambda: VGroup(*[
|
||||||
|
self.get_v_line(dot)
|
||||||
|
for dot in dots
|
||||||
|
]))
|
||||||
|
|
||||||
|
def get_v_line(self, dot):
|
||||||
|
x_axis = self.axes.x_axis
|
||||||
|
bottom = dot.get_bottom()
|
||||||
|
x = x_axis.p2n(bottom)
|
||||||
|
proj_point = x_axis.n2p(x)
|
||||||
|
return DashedLine(
|
||||||
|
proj_point, bottom,
|
||||||
|
**self.v_line_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_rod_pieces(self, dots):
|
||||||
|
axis = self.axes.x_axis
|
||||||
|
factor = 1 - np.exp(-(0.8 / self.step_size)**2)
|
||||||
|
width = factor * self.step_size
|
||||||
|
|
||||||
|
pieces = VGroup()
|
||||||
|
for dot in dots:
|
||||||
|
piece = Line(ORIGIN, width * RIGHT)
|
||||||
|
piece.set_stroke(width=5)
|
||||||
|
piece.move_to(dot)
|
||||||
|
piece.set_y(axis.get_center()[1])
|
||||||
|
piece.dot = dot
|
||||||
|
piece.add_updater(
|
||||||
|
lambda p: p.match_color(p.dot)
|
||||||
|
)
|
||||||
|
pieces.add(piece)
|
||||||
|
return pieces
|
||||||
|
|
||||||
|
def update_dot_color(self, dot):
|
||||||
|
y = self.axes.y_axis.p2n(dot.get_center())
|
||||||
|
dot.set_color(self.y_to_color(y))
|
||||||
|
|
||||||
|
def update_dots(self, dots, dt):
|
||||||
|
for ds in zip(dots, dots[1:], dots[2:]):
|
||||||
|
points = [d.get_center() for d in ds]
|
||||||
|
x0, x1, x2 = [p[0] for p in points]
|
||||||
|
dx = x1 - x0
|
||||||
|
y0, y1, y2 = [p[1] for p in points]
|
||||||
|
|
||||||
|
self.update_dot(
|
||||||
|
dot=ds[1],
|
||||||
|
dt=dt,
|
||||||
|
mean_diff=0.5 * (y2 - 2 * y1 + y0) / dx
|
||||||
|
)
|
||||||
|
if ds[0] is dots[0]:
|
||||||
|
self.update_dot(
|
||||||
|
dot=ds[0],
|
||||||
|
dt=dt,
|
||||||
|
mean_diff=(y1 - y0) / dx
|
||||||
|
)
|
||||||
|
elif ds[-1] is dots[-1]:
|
||||||
|
self.update_dot(
|
||||||
|
dot=ds[-1],
|
||||||
|
dt=dt,
|
||||||
|
mean_diff=(y1 - y2) / dx
|
||||||
|
)
|
||||||
|
|
||||||
|
def update_dot(self, dot, dt, mean_diff):
|
||||||
|
dot.shift(mean_diff * self.alpha * dt * UP)
|
||||||
|
|
||||||
|
|
||||||
|
class DiscreteEvolutionPoint25(ShowNewRuleAtDiscreteBoundary):
|
||||||
|
CONFIG = {
|
||||||
|
"step_size": 0.25,
|
||||||
|
"alpha": 0.5,
|
||||||
|
"wait_time": 30,
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.add_axes()
|
||||||
|
self.set_points()
|
||||||
|
self.add_clock()
|
||||||
|
self.let_evolve()
|
||||||
|
|
||||||
|
|
||||||
|
class DiscreteEvolutionPoint1(DiscreteEvolutionPoint25):
|
||||||
|
CONFIG = {
|
||||||
|
"step_size": 0.1,
|
||||||
|
"v_line_config": {
|
||||||
|
"stroke_width": 1,
|
||||||
|
},
|
||||||
|
"wait_time": 30,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FlatEdgesForDiscreteEvolution(DiscreteEvolutionPoint1):
|
||||||
|
CONFIG = {
|
||||||
|
"wait_time": 20,
|
||||||
|
"step_size": 0.1,
|
||||||
|
}
|
||||||
|
|
||||||
|
def let_evolve(self):
|
||||||
|
lines = VGroup(*[
|
||||||
|
Line(LEFT, RIGHT)
|
||||||
|
for x in range(2)
|
||||||
|
])
|
||||||
|
lines.set_width(1.5)
|
||||||
|
lines.set_stroke(WHITE, 5, opacity=0.5)
|
||||||
|
lines.add_updater(self.update_lines)
|
||||||
|
|
||||||
|
turn_animation_into_updater(
|
||||||
|
ShowCreation(lines, run_time=2)
|
||||||
|
)
|
||||||
|
self.add(lines)
|
||||||
|
|
||||||
|
super().let_evolve()
|
||||||
|
|
||||||
|
def update_lines(self, lines):
|
||||||
|
dots = self.dots
|
||||||
|
for line, dot in zip(lines, [dots[0], dots[-1]]):
|
||||||
|
line.move_to(dot)
|
||||||
|
|
||||||
|
|
||||||
|
class FlatEdgesForDiscreteEvolutionTinySteps(FlatEdgesForDiscreteEvolution):
|
||||||
|
CONFIG = {
|
||||||
|
"step_size": 0.025,
|
||||||
|
"wait_time": 0,
|
||||||
|
"v_line_config": {
|
||||||
|
"positive_space_ratio": 1,
|
||||||
|
"stroke_opacity": 0.5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1657,7 +1657,6 @@ class StraightLine3DGraph(TemperatureGraphScene):
|
||||||
return self.c * x
|
return self.c * x
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SimulateLinearGraph(SimulateRealSineCurve):
|
class SimulateLinearGraph(SimulateRealSineCurve):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"axes_config": {
|
"axes_config": {
|
||||||
|
@ -1753,3 +1752,46 @@ class EmphasizeBoundaryPoints(SimulateLinearGraph):
|
||||||
super().let_play()
|
super().let_play()
|
||||||
|
|
||||||
|
|
||||||
|
class FlatEdgesContinuousEvolution(ShowEvolvingTempGraphWithArrows):
|
||||||
|
CONFIG = {
|
||||||
|
"wait_time": 30,
|
||||||
|
"freq_amplitude_pairs": [
|
||||||
|
(1, 0.5),
|
||||||
|
(2, 1),
|
||||||
|
(3, 0.5),
|
||||||
|
(4, 0.3),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.add_axes()
|
||||||
|
self.add_graph()
|
||||||
|
self.add_clock()
|
||||||
|
self.add_rod()
|
||||||
|
# self.add_arrows()
|
||||||
|
self.initialize_updaters()
|
||||||
|
self.add_boundary_lines()
|
||||||
|
self.let_play()
|
||||||
|
|
||||||
|
def add_boundary_lines(self):
|
||||||
|
|
||||||
|
lines = VGroup(*[
|
||||||
|
Line(LEFT, RIGHT)
|
||||||
|
for x in range(2)
|
||||||
|
])
|
||||||
|
lines.set_width(1.5)
|
||||||
|
lines.set_stroke(WHITE, 5, opacity=0.5)
|
||||||
|
lines.add_updater(self.update_lines)
|
||||||
|
|
||||||
|
turn_animation_into_updater(
|
||||||
|
ShowCreation(lines, run_time=2)
|
||||||
|
)
|
||||||
|
self.add(lines)
|
||||||
|
|
||||||
|
def update_lines(self, lines):
|
||||||
|
graph = self.graph
|
||||||
|
lines[0].move_to(graph.get_start())
|
||||||
|
lines[1].move_to(graph.get_end())
|
||||||
|
|
||||||
|
def initial_function(self, x):
|
||||||
|
return ShowEvolvingTempGraphWithArrows.initial_function(self, x)
|
||||||
|
|
|
@ -505,7 +505,7 @@ class DerivativesOfLinearFunction(WriteHeatEquationTemplate):
|
||||||
dx_group.arrange(RIGHT)
|
dx_group.arrange(RIGHT)
|
||||||
for arrow, char, vect in zip(arrows, "xxt", [UP, UP, RIGHT]):
|
for arrow, char, vect in zip(arrows, "xxt", [UP, UP, RIGHT]):
|
||||||
label = TexMobject(
|
label = TexMobject(
|
||||||
"\\partial \\over \\partial {%s}"%char,
|
"\\partial \\over \\partial {%s}" % char,
|
||||||
**self.tex_mobject_config
|
**self.tex_mobject_config
|
||||||
)
|
)
|
||||||
label.scale(0.7)
|
label.scale(0.7)
|
||||||
|
@ -541,3 +541,13 @@ class DerivativesOfLinearFunction(WriteHeatEquationTemplate):
|
||||||
TransformFromCopy(func[-3:], dt_T)
|
TransformFromCopy(func[-3:], dt_T)
|
||||||
)
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
|
||||||
|
class FlatAtBoundaryWords(Scene):
|
||||||
|
def construct(self):
|
||||||
|
words = TextMobject(
|
||||||
|
"Flat at boundary\\\\"
|
||||||
|
"for all $t > 0$"
|
||||||
|
)
|
||||||
|
self.play(Write(words))
|
||||||
|
self.wait()
|
||||||
|
|
Loading…
Add table
Reference in a new issue