from manimlib.imports import * from active_projects.diffyq.part2.wordy_scenes import * class ThreeMainObservations(Scene): def construct(self): fourier = ImageMobject("Joseph Fourier") name = TextMobject("Joseph Fourier") name.match_width(fourier) name.next_to(fourier, DOWN, SMALL_BUFF) fourier.add(name) fourier.set_height(5) fourier.to_corner(DR) fourier.shift(LEFT) bubble = ThoughtBubble( direction=RIGHT, height=3, width=4, ) bubble.move_tip_to(fourier.get_corner(UL) + 0.5 * DR) observations = VGroup( TextMobject( "1)", "Sine = Nice", ), TextMobject( "2)", "Linearity" ), TextMobject( "3)", "Fourier series" ), ) # heart = SuitSymbol("hearts") # heart.replace(observations[0][2]) # observations[0][2].become(heart) # observations[0][1].add(happiness) # observations[2][2].align_to( # observations[2][1], LEFT, # ) observations.arrange( DOWN, aligned_edge=LEFT, buff=2 * LARGE_BUFF, ) observations.set_height(FRAME_HEIGHT - 2) observations.to_corner(UL, buff=LARGE_BUFF) self.add(fourier) self.play(ShowCreation(bubble)) self.wait() self.play(LaggedStart(*[ TransformFromCopy(bubble, observation[0]) for observation in observations ], lag_ratio=0.2)) self.play( FadeOut(fourier), FadeOut(bubble), ) self.wait() for obs in observations: self.play(FadeInFrom(obs[1], LEFT)) self.wait() class LastChapterWrapper(Scene): def construct(self): full_rect = FullScreenFadeRectangle( fill_color=DARK_GREY, fill_opacity=1, ) rect = ScreenRectangle(height=6) rect.set_stroke(WHITE, 2) rect.set_fill(BLACK, 1) title = TextMobject("Last chapter") title.scale(2) title.to_edge(UP) rect.next_to(title, DOWN) self.add(full_rect) self.play( FadeIn(rect), Write(title, run_time=2), ) self.wait() class ThreeConstraints(WriteHeatEquationTemplate): def construct(self): self.cross_out_solving() self.show_three_conditions() def cross_out_solving(self): equation = self.get_d1_equation() words = TextMobject("Solve this equation") words.to_edge(UP) equation.next_to(words, DOWN) cross = Cross(words) self.add(words, equation) self.wait() self.play(ShowCreation(cross)) self.wait() self.equation = equation self.to_remove = VGroup(words, cross) def show_three_conditions(self): equation = self.equation to_remove = self.to_remove title = TexMobject( "\\text{Constraints }" "T({x}, {t})" "\\text{ must satisfy:}", **self.tex_mobject_config ) title.to_edge(UP) items = VGroup( TextMobject("1)", "The PDE"), TextMobject("2)", "Boundary condition"), TextMobject("3)", "Initial condition"), ) items.scale(0.7) items.arrange(RIGHT, buff=LARGE_BUFF) items.set_width(FRAME_WIDTH - 2) items.next_to(title, DOWN, LARGE_BUFF) items[1].set_color(MAROON_B) items[2].set_color(RED) bc_paren = TextMobject("(Explained soon)") bc_paren.scale(0.7) bc_paren.next_to(items[1], DOWN) self.play( FadeInFromDown(title), FadeOutAndShift(to_remove, UP), equation.scale, 0.6, equation.next_to, items[0], DOWN, equation.shift_onto_screen, LaggedStartMap(FadeIn, [ items[0], items[1][0], items[2][0], ]) ) self.wait() self.play(Write(items[1][1])) bc_paren.match_y(equation) self.play(FadeInFrom(bc_paren, UP)) self.wait(2) self.play(Write(items[2][1])) self.wait(2) self.title = title self.items = items self.pde = equation self.bc_paren = bc_paren class RectAroundEquation(WriteHeatEquationTemplate): def construct(self): eq = self.get_d1_equation() self.play(ShowCreationThenFadeAround(eq)) class BorderRect(Scene): def construct(self): rect = FullScreenFadeRectangle() rect.set_stroke(WHITE, 3) rect.set_fill(opacity=0) self.add(rect) class SeekIdealized(Scene): def construct(self): phrases = VGroup(*[ TextMobject( "Seek", text, "problems", tex_to_color_map={ "realistic": GREEN, "{idealized}": YELLOW, "over-idealized": YELLOW, "general": BLUE, } ) for text in [ "realistic", "{idealized}", "over-idealized", "general", ] ]) phrases.scale(2) words = VGroup() for phrase in phrases: phrase.center() word = phrase[1] words.add(word) phrase.remove(word) arrow = Vector(DOWN) arrow.set_stroke(WHITE, 6) arrow.next_to(words[3], UP) low_arrow = arrow.copy() low_arrow.next_to(words[3], DOWN) solutions = TextMobject("solutions") solutions.scale(2) solutions.move_to(phrases[3][1], UL) models = TextMobject("models") models.scale(2) models.next_to( words[0], RIGHT, buff=0.35, aligned_edge=DOWN ) phrases.center() phrase = phrases[0] self.add(phrase) self.add(words[0]) self.wait() words[0].save_state() self.play( words[0].to_edge, DOWN, words[0].set_opacity, 0.5, Transform(phrase, phrases[1]), FadeInFrom(words[1], UP) ) self.wait() # self.play( # words[1].move_to, words[2], RIGHT, # FadeIn(words[2]), # Transform(phrase, phrases[2]) # ) # self.wait() self.play( words[1].next_to, arrow, UP, ShowCreation(arrow), MaintainPositionRelativeTo( phrase, words[1] ), FadeInFrom(solutions, LEFT), FadeIn(words[3]), ) self.wait() words[0].generate_target() words[0].target.next_to(low_arrow, DOWN) words[0].target.set_opacity(1) models.shift( words[0].target.get_center() - words[0].saved_state.get_center() ) self.play( MoveToTarget(words[0]), ShowCreation(low_arrow), FadeInFrom(models, LEFT) ) self.wait() class SecondDerivativeOfSine(Scene): def construct(self): equation = TexMobject( "{d^2 \\over d{x}^2}", "\\cos\\left({x}\\right) =", "-\\cos\\left({x}\\right)", tex_to_color_map={ "{x}": GREEN, } ) self.add(equation) class EquationAboveSineAnalysis(WriteHeatEquationTemplate): def construct(self): equation = self.get_d1_equation() equation.to_edge(UP) equation.shift(2 * LEFT) eq_index = equation.index_of_part_by_tex("=") lhs = equation[:eq_index] eq = equation[eq_index] rhs = equation[eq_index + 1:] t_terms = equation.get_parts_by_tex("{t}")[1:] t_terms.save_state() zeros = VGroup(*[ TexMobject("0").replace(t, dim_to_match=1) for t in t_terms ]) zeros.align_to(t_terms, DOWN) new_rhs = TexMobject( "=", "-\\alpha \\cdot {T}", "({x}, 0)", **self.tex_mobject_config ) # new_rhs.move_to(equation.get_right()) # new_rhs.next_to(equation, DOWN, MED_LARGE_BUFF) # new_rhs.align_to(eq, LEFT) new_rhs.next_to(equation, RIGHT) new_rhs.shift(SMALL_BUFF * DOWN) self.add(equation) self.play(ShowCreationThenFadeAround(rhs)) self.wait() self.play( FadeOutAndShift(t_terms, UP), FadeInFrom(zeros, DOWN), ) t_terms.fade(1) self.wait() self.play( # VGroup(equation, zeros).next_to, # new_rhs, LEFT, FadeIn(new_rhs), ) self.wait() self.play( VGroup( lhs[6:], eq, rhs, new_rhs[0], new_rhs[-3:], zeros, ).fade, 0.5, ) self.play(ShowCreationThenFadeAround(lhs[:6])) self.play(ShowCreationThenFadeAround(new_rhs[1:-3])) self.wait() class ExpVideoWrapper(Scene): def construct(self): self.add(FullScreenFadeRectangle( fill_color=DARKER_GREY, fill_opacity=1, )) screen = ImageMobject("eoc_chapter5_thumbnail") screen.set_height(6) rect = SurroundingRectangle(screen, buff=0) rect.set_stroke(WHITE, 2) screen.add(rect) title = TextMobject("Need a refresher?") title.scale(1.5) title.to_edge(UP) screen.next_to(title, DOWN) screen.center() self.play( # FadeInFrom(title, LEFT), FadeInFrom(screen, DOWN), ) self.wait() class ShowSinExpDerivatives(WriteHeatEquationTemplate): CONFIG = { "tex_mobject_config": { "tex_to_color_map": { "{0}": WHITE, "\\partial": WHITE, "=": WHITE, } } } def construct(self): pde = self.get_d1_equation_without_inputs() pde.to_edge(UP) pde.generate_target() new_rhs = TexMobject( "=- \\alpha \\cdot T", **self.tex_mobject_config, ) new_rhs.next_to(pde, RIGHT) new_rhs.align_to(pde.get_part_by_tex("alpha"), DOWN) equation1 = TexMobject( "T({x}, {0}) = \\sin\\left({x}\\right)", **self.tex_mobject_config ) equation2 = TexMobject( "T({x}, {t}) = \\sin\\left({x}\\right)", "e^{-\\alpha{t}}", **self.tex_mobject_config ) for eq in equation1, equation2: eq.next_to(pde, DOWN, MED_LARGE_BUFF) eq2_part1 = equation2[:len(equation1)] eq2_part2 = equation2[len(equation1):] # Rectangles exp_rect = SurroundingRectangle(eq2_part2) exp_rect.set_stroke(RED, 3) sin_rect = SurroundingRectangle( eq2_part1[-3:] ) sin_rect.set_color(BLUE) VGroup(pde.target, new_rhs).center().to_edge(UP) # Show proposed solution self.add(pde) self.add(equation1) self.wait() self.play( MoveToTarget(pde), FadeInFrom(new_rhs, LEFT) ) self.wait() self.play( ReplacementTransform(equation1, eq2_part1), FadeIn(eq2_part2), ) self.play(ShowCreation(exp_rect)) self.wait() self.play(FadeOut(exp_rect)) # Take partial derivatives wrt x q_mark = TexMobject("?") q_mark.next_to(pde.get_part_by_tex("="), UP) q_mark.set_color(RED) arrow1 = Vector(3 * DOWN + 1 * RIGHT, color=WHITE) arrow1.scale(1.2 / arrow1.get_length()) arrow1.next_to( eq2_part2.get_corner(DL), DOWN, MED_LARGE_BUFF ) ddx_label1 = TexMobject( "\\partial \\over \\partial {x}", **self.tex_mobject_config, ) ddx_label1.scale(0.7) ddx_label1.next_to( arrow1.point_from_proportion(0.8), UR, SMALL_BUFF ) pde_ddx = VGroup( *pde.get_parts_by_tex("\\partial")[2:], pde.get_parts_by_tex("\\over")[1], pde.get_part_by_tex("{x}"), ) pde_ddx_rect = SurroundingRectangle(pde_ddx) pde_ddx_rect.set_color(GREEN) eq2_part2_rect = SurroundingRectangle(eq2_part2) dx = TexMobject( "\\cos\\left({x}\\right)", "e^{-\\alpha {t}}", **self.tex_mobject_config ) ddx = TexMobject( "-\\sin\\left({x}\\right)", "e^{-\\alpha {t}}", **self.tex_mobject_config ) dx.next_to(arrow1, DOWN) dx.align_to(eq2_part2, RIGHT) x_shift = arrow1.get_end()[0] - arrow1.get_start()[0] x_shift *= 2 dx.shift(x_shift * RIGHT) arrow2 = arrow1.copy() arrow2.next_to(dx, DOWN) arrow2.shift(MED_SMALL_BUFF * RIGHT) dx_arrows = VGroup(arrow1, arrow2) ddx_label2 = ddx_label1.copy() ddx_label2.shift( arrow2.get_center() - arrow1.get_center() ) ddx.next_to(arrow2, DOWN) ddx.align_to(eq2_part2, RIGHT) ddx.shift(2 * x_shift * RIGHT) rhs = equation2[-6:] self.play( FadeInFromDown(q_mark) ) self.play( ShowCreation(pde_ddx_rect) ) self.wait() self.play( LaggedStart( GrowArrow(arrow1), GrowArrow(arrow2), ), TransformFromCopy( pde_ddx[0], ddx_label1 ), TransformFromCopy( pde_ddx[0], ddx_label2 ), ) self.wait() self.play( TransformFromCopy(rhs, dx) ) self.wait() self.play( FadeIn(eq2_part2_rect) ) self.play( Transform( eq2_part2_rect, SurroundingRectangle(dx[-3:]) ) ) self.play( FadeOut(eq2_part2_rect) ) self.wait() self.play( TransformFromCopy(dx, ddx) ) self.play( FadeIn( SurroundingRectangle(ddx).match_style( pde_ddx_rect ) ) ) self.wait() # Take partial derivative wrt t pde_ddt = pde[:pde.index_of_part_by_tex("=") - 1] pde_ddt_rect = SurroundingRectangle(pde_ddt) dt_arrow = Arrow( arrow1.get_start(), arrow2.get_end() + RIGHT, buff=0 ) dt_arrow.flip(UP) dt_arrow.next_to(dx_arrows, LEFT, MED_LARGE_BUFF) dt_label = TexMobject( "\\partial \\over \\partial {t}", **self.tex_mobject_config, ) dt_label.scale(1) dt_label.next_to( dt_arrow.get_center(), UL, SMALL_BUFF, ) rhs_copy = rhs.copy() rhs_copy.next_to(dt_arrow.get_end(), DOWN) rhs_copy.shift(MED_LARGE_BUFF * LEFT) rhs_copy.match_y(ddx) minus_alpha_in_exp = rhs_copy[-3][1:].copy() minus_alpha_in_exp.set_color(RED) minus_alpha = TexMobject("-\\alpha") minus_alpha.next_to(rhs_copy, LEFT) minus_alpha.align_to(rhs_copy[0][0], DOWN) dot = TexMobject("\\cdot") dot.move_to(midpoint( minus_alpha.get_right(), rhs_copy.get_left(), )) self.play( TransformFromCopy( pde_ddx_rect, pde_ddt_rect, ) ) self.play( GrowArrow(dt_arrow), TransformFromCopy( pde_ddt, dt_label, ) ) self.wait() self.play(TransformFromCopy(rhs, rhs_copy)) self.play(FadeIn(minus_alpha_in_exp)) self.play( ApplyMethod( minus_alpha_in_exp.replace, minus_alpha, path_arc=TAU / 4 ), FadeIn(dot), ) self.play( FadeIn(minus_alpha), FadeOut(minus_alpha_in_exp), ) self.wait() rhs_copy.add(minus_alpha, dot) self.play( FadeIn(SurroundingRectangle(rhs_copy)) ) self.wait() # checkmark = TexMobject("\\checkmark") checkmark.set_color(GREEN) checkmark.move_to(q_mark, DOWN) self.play( FadeInFromDown(checkmark), FadeOutAndShift(q_mark, UP) ) self.wait() class DerivativesOfLinearFunction(WriteHeatEquationTemplate): CONFIG = { "tex_mobject_config": { "tex_to_color_map": { "{c}": WHITE, } } } def construct(self): func = TexMobject( "T({x}, {t}) = {c} \\cdot {x}", **self.tex_mobject_config ) dx_T = TexMobject("{c}", **self.tex_mobject_config) ddx_T = TexMobject("0") dt_T = TexMobject("0") for mob in func, dx_T, ddx_T, dt_T: mob.scale(1.5) func.generate_target() arrows = VGroup(*[ Vector(1.5 * RIGHT, color=WHITE) for x in range(3) ]) dx_arrows = arrows[:2] dt_arrow = arrows[2] dt_arrow.rotate(-TAU / 4) dx_group = VGroup( func.target, dx_arrows[0], dx_T, dx_arrows[1], ddx_T, ) dx_group.arrange(RIGHT) for arrow, char, vect in zip(arrows, "xxt", [UP, UP, RIGHT]): label = TexMobject( "\\partial \\over \\partial {%s}" % char, **self.tex_mobject_config ) label.scale(0.7) label.next_to(arrow.get_center(), vect) arrow.add(label) dt_arrow.shift( func.target[-3:].get_bottom() + MED_SMALL_BUFF * DOWN - dt_arrow.get_start(), ) dt_T.next_to(dt_arrow.get_end(), DOWN) self.play(FadeInFromDown(func)) self.wait() self.play( MoveToTarget(func), LaggedStartMap(Write, dx_arrows), run_time=1, ) self.play( TransformFromCopy(func[-3:], dx_T), path_arc=-TAU / 4, ) self.play( TransformFromCopy(dx_T, ddx_T), path_arc=-TAU / 4, ) self.wait() # dt self.play(Write(dt_arrow)) self.play( TransformFromCopy(func[-3:], dt_T) ) self.wait() class FlatAtBoundaryWords(Scene): def construct(self): words = self.get_bc_words() self.play(Write(words)) self.wait() def get_bc_words(self): return TextMobject( "Flat at boundary\\\\" "for all", "${t}$", "$> 0$", ) class WriteOutBoundaryCondition(FlatAtBoundaryWords, ThreeConstraints, MovingCameraScene): def construct(self): self.force_skipping() ThreeConstraints.construct(self) self.revert_to_original_skipping_status() self.add_ic() self.write_bc_words() self.write_bc_equation() def add_ic(self): image = ImageMobject("temp_initial_condition_example") image.set_width(3) border = SurroundingRectangle(image, buff=SMALL_BUFF) border.shift(SMALL_BUFF * UP) border.set_stroke(WHITE, 2) group = Group(image, border) group.next_to(self.items[2], DOWN) self.add(group) def write_bc_words(self): bc_paren = self.bc_paren bc_words = self.get_bc_words() bc_words.match_width(self.items[1][1]) bc_words.move_to(bc_paren, UP) bc_words.set_color_by_tex("{t}", YELLOW) self.play(ShowCreationThenFadeAround( VGroup(self.items[0], self.pde) )) self.play( FadeOutAndShift(bc_paren, UP), FadeInFrom(bc_words, DOWN), ) self.wait() self.bc_words = bc_words def write_bc_equation(self): bc_words = self.bc_words equation = TexMobject( "{\\partial {T} \\over \\partial {x}}(0, {t}) = ", "{\\partial {T} \\over \\partial {x}}(L, {t}) = ", "0", **self.tex_mobject_config, ) equation.next_to(bc_words, DOWN, MED_LARGE_BUFF) self.play( self.camera_frame.shift, 0.8 * DOWN, ) self.play(FadeInFrom(equation, UP)) self.wait() class HeatEquationFrame(WriteHeatEquationTemplate): def construct(self): equation = self.get_d1_equation() equation.to_edge(UP, buff=MED_SMALL_BUFF) ddx = equation[-11:] dt = equation[:11] full_rect = FullScreenFadeRectangle( fill_color=DARK_GREY, fill_opacity=1, ) smaller_rect = ScreenRectangle( height=6, fill_color=BLACK, fill_opacity=1, stroke_color=WHITE, stroke_width=2, ) smaller_rect.next_to(equation, DOWN) self.add(full_rect) self.add(smaller_rect) self.add(equation) self.wait() self.play(ShowCreationThenFadeAround( ddx, surrounding_rectangle_config={ "stroke_color": GREEN, } )) self.wait() self.play(ShowCreationThenFadeAround(dt)) self.wait() class CompareFreqDecays1to2(Scene): CONFIG = { "freqs": [1, 2] } def construct(self): background = FullScreenFadeRectangle( fill_color=DARKER_GREY, fill_opacity=1, ) screens = VGroup(*[ ScreenRectangle( height=4, fill_color=BLACK, fill_opacity=1, stroke_width=1, stroke_color=WHITE, ) for x in range(2) ]) screens.arrange(RIGHT) screens.set_width(FRAME_WIDTH - 1) formulas = VGroup(*[ self.get_formula(freq) for freq in self.freqs ]) for formula, screen in zip(formulas, screens): formula.next_to(screen, UP) self.add(background) self.add(screens) self.add(formulas) self.wait() def get_formula(self, freq): f_str = str(freq) return TexMobject( "\\cos\\left(%s \\cdot {x}\\right)" % f_str, "e^{-\\alpha \\cdot %s^2 \\cdot {t}}" % f_str, tex_to_color_map={ "{x}": GREEN, "{t}": YELLOW, f_str: MAROON_B, } ) class CompareFreqDecays1to4(CompareFreqDecays1to2): CONFIG = { "freqs": [1, 4], } class CompareFreqDecays2to4(CompareFreqDecays1to2): CONFIG = { "freqs": [2, 4], } class WorryAboutGenerality(TeacherStudentsScene, WriteHeatEquationTemplate): def construct(self): eq = self.get_d1_equation() diffyq = self.get_diffyq_set() is_in = TexMobject("\\in") is_in.scale(2) group = VGroup(eq, is_in, diffyq) group.arrange(RIGHT, buff=MED_LARGE_BUFF) group.to_edge(UP) arrow = Vector(DOWN) arrow.set_stroke(WHITE, 5) arrow.next_to(eq, DOWN) themes = TextMobject("Frequent themes") themes.scale(1.5) themes.next_to(arrow, DOWN) self.play( self.get_student_changes( "sad", "tired", "pleading" ), self.teacher.change, "raise_right_hand", FadeInFromDown(eq) ) self.play(Write(group[1:])) self.wait(2) self.play( ShowCreation(arrow), self.get_student_changes(*3 * ["pondering"]), ) self.play( FadeInFrom(themes, UP), self.get_student_changes(*3 * ["thinking"]), self.teacher.change, "happy" ) self.wait(4) # def get_d1_equation(self): # result = super().get_d1_equation() # lp, rp = parens = TexMobject("(", ")") # parens.match_height(result) # lp.next_to(result, LEFT, SMALL_BUFF) # rp.next_to(result, RIGHT, SMALL_BUFF) # result.add_to_back(lp) # result.add(rp) # return result def get_diffyq_set(self): words = TextMobject( "Differential\\\\equations" ) words.scale(1.5) words.set_color(BLUE) lb = Brace(words, LEFT) rb = Brace(words, RIGHT) return VGroup(lb, words, rb)