cleanup for the presentation
This commit is contained in:
82
nbody/presentation/helpers.typ
Normal file
82
nbody/presentation/helpers.typ
Normal file
@@ -0,0 +1,82 @@
|
||||
// Helpers for code block displaying
|
||||
|
||||
#import "@preview/based:0.2.0": base64
|
||||
|
||||
#let code_font_scale = 0.6em
|
||||
|
||||
#let cell_matcher(cell, cell_tag) = {
|
||||
// Matching function to check if a cell has a specific tag
|
||||
if cell.cell_type != "code" {
|
||||
return false
|
||||
}
|
||||
let metadata = cell.metadata
|
||||
if metadata.keys().contains("tags") == false {
|
||||
return false
|
||||
}
|
||||
return cell.metadata.tags.contains(cell_tag)
|
||||
}
|
||||
|
||||
|
||||
#let code_cell(fcontent, cell_tag) = {
|
||||
// Extract the content of a cell and display it as a code block
|
||||
let cells = fcontent.cells
|
||||
let matching_cell = cells.find(x => cell_matcher(x, cell_tag))
|
||||
|
||||
let cell_content = matching_cell.source
|
||||
let single_line = cell_content.fold("", (acc, x) => acc + x)
|
||||
|
||||
text(
|
||||
raw(
|
||||
single_line,
|
||||
lang: "python",
|
||||
block: true
|
||||
),
|
||||
size: code_font_scale
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
#let image_cell(fcontent, cell_tag) = {
|
||||
// Extract the output (image) of a cell and display it as an image
|
||||
let cells = fcontent.cells
|
||||
let matching_cell = cells.find(x => cell_matcher(x, cell_tag))
|
||||
|
||||
let outputs = matching_cell.outputs
|
||||
for output in outputs {
|
||||
let image_data = output.at("data", default: (:)).at("image/png", default: none)
|
||||
if image_data != none {
|
||||
align(
|
||||
center,
|
||||
image.decode(
|
||||
base64.decode(image_data),
|
||||
// height: 70% // the height should be set by the caller. This gives the flexibility to adjust the height of the image
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#let code_reference_cell(fcontent, cell_tag) = {
|
||||
// Extract the output (text) of a cell and display it as a code block
|
||||
// This is useful for showing the code of imported functions
|
||||
let cells = fcontent.cells
|
||||
let matching_cell = cells.find(x => cell_matcher(x, cell_tag))
|
||||
|
||||
let outputs = matching_cell.outputs
|
||||
for output in outputs {
|
||||
let cell_output = output.at("text", default: (:))
|
||||
if cell_output != none {
|
||||
let single_line = cell_output.join("")
|
||||
text(
|
||||
raw(
|
||||
single_line,
|
||||
lang: "python",
|
||||
block: true
|
||||
),
|
||||
size: code_font_scale
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
@@ -1,7 +1,6 @@
|
||||
#import "@preview/diatypst:0.2.0": *
|
||||
#import "@preview/based:0.2.0": base64
|
||||
|
||||
#set text(font: "Cantarell")
|
||||
// #set text(font: "Cantarell")
|
||||
// #set heading(numbering: (..nums)=>"")
|
||||
|
||||
#show: slides.with(
|
||||
@@ -11,74 +10,25 @@
|
||||
authors: ("Rémy Moll"),
|
||||
toc: false,
|
||||
// layout: "large",
|
||||
// ratio: 16/9,
|
||||
)
|
||||
|
||||
|
||||
#import "helpers.typ"
|
||||
|
||||
// KINDA COOL:
|
||||
// _diatypst_ defines some default styling for elements, e.g Terms created with ```typc / Term: Definition``` will look like this
|
||||
|
||||
// / *Term*: Definition
|
||||
|
||||
|
||||
|
||||
// Helpers for code block displaying
|
||||
|
||||
#let cell_matcher(cell, cell_tag) = {
|
||||
if cell.cell_type != "code" {
|
||||
return false
|
||||
}
|
||||
let metadata = cell.metadata
|
||||
if metadata.keys().contains("tags") == false {
|
||||
return false
|
||||
}
|
||||
|
||||
return cell.metadata.tags.contains(cell_tag)
|
||||
}
|
||||
|
||||
#let code_cell(fcontent, cell_tag) = {
|
||||
let cells = fcontent.cells
|
||||
let matching_cell = cells.find(x => cell_matcher(x, cell_tag))
|
||||
|
||||
let cell_content = matching_cell.source
|
||||
// format the cell content
|
||||
let single_line = cell_content.fold("", (acc, x) => acc + x)
|
||||
|
||||
text(
|
||||
raw(
|
||||
single_line,
|
||||
lang: "python",
|
||||
block: true
|
||||
),
|
||||
size: 0.8em
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#let image_cell(fcontent, cell_tag) = {
|
||||
let cells = fcontent.cells
|
||||
let matching_cell = cells.find(x => cell_matcher(x, cell_tag))
|
||||
|
||||
let outputs = matching_cell.outputs
|
||||
for output in outputs {
|
||||
let image_data = output.at("data", default: (:)).at("image/png", default: none)
|
||||
if image_data != none {
|
||||
align(
|
||||
center,
|
||||
image.decode(
|
||||
base64.decode(image_data),
|
||||
// format: "png",
|
||||
height: 70%
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Where is the code?
|
||||
// Setup of code location
|
||||
#let t1 = json("../task1.ipynb")
|
||||
#let t2 = json("../task2-particle-mesh.ipynb")
|
||||
|
||||
|
||||
|
||||
// Content
|
||||
// Finally - The real content
|
||||
= N-body forces and analytical solutions
|
||||
|
||||
== Objective
|
||||
@@ -87,62 +37,188 @@ Implement naive N-body force computation and get an intuition of the challenges:
|
||||
- computation time
|
||||
- stability
|
||||
|
||||
$=>$ still useful to compute basic quantities of the system, but too limited for large systems or the dynamical evolution of the system
|
||||
$==>$ still useful to compute basic quantities of the system, but too limited for large systems or the dynamical evolution of the system
|
||||
|
||||
|
||||
== Overview - the system
|
||||
Get a feel for the particles and their distribution. [Code at @task1:plot_particle_distribution[]]
|
||||
#image_cell(t1, "plot_particle_distribution")
|
||||
Get a feel for the particles and their distribution. [#link(<task1:plot_particle_distribution>)[code]]
|
||||
|
||||
#code_cell(t1, "plotting")
|
||||
|
||||
== Inspecting the data
|
||||
#code_cell(t2, "plotting")
|
||||
|
||||
#image_cell(t2, "plotting")
|
||||
#columns(2)[
|
||||
#helpers.image_cell(t1, "plot_particle_distribution")
|
||||
Note: for visibility the outer particles are not shown.
|
||||
#colbreak()
|
||||
The system at hand is characterized by:
|
||||
- $N ~ 10^4$ stars
|
||||
- a _spherical_ distribution
|
||||
|
||||
$==>$ treat the system as a *globular cluster*
|
||||
|
||||
]
|
||||
|
||||
|
||||
== Density
|
||||
Some images about the density
|
||||
We compare the computed density with the analytical model provided by the _Hernquist_ model:
|
||||
|
||||
#grid(
|
||||
columns: (1fr, 2fr),
|
||||
inset: 0.5em,
|
||||
block[
|
||||
$
|
||||
rho(r) = M/(2 pi) a / (r dot (r + a)^3)
|
||||
$
|
||||
where we infer $a$ from the half-mass radius:
|
||||
$
|
||||
r_"hm" = (1 + sqrt(2)) dot a
|
||||
$
|
||||
|
||||
#text(size: 0.6em)[
|
||||
Density sampling [#link(<task1:function_density_distribution>)[code]];
|
||||
]
|
||||
],
|
||||
block[
|
||||
#helpers.image_cell(t1, "plot_density_distribution")
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
#block(
|
||||
height: 1fr,
|
||||
)
|
||||
|
||||
|
||||
== Force computation
|
||||
// N Body and variations
|
||||
#grid(
|
||||
columns: (2fr, 1fr),
|
||||
inset: 0.5em,
|
||||
block[
|
||||
#helpers.image_cell(t1, "plot_force_radial")
|
||||
// The radial force is computed as the sum of the forces of all particles in the system.
|
||||
#text(size: 0.6em)[
|
||||
Analytical force [#link(<task1:function_analytical_forces>)[code]];
|
||||
$N^2$ force [#link(<task1:function_n2_forces>)[code]];
|
||||
$epsilon$ computation [#link(<task1:function_interparticle_distance>)[code]];
|
||||
]
|
||||
],
|
||||
block[
|
||||
Discussion:
|
||||
- the analytical method replicates the behavior accurately
|
||||
- at small softenings the $N^2$ method has noisy artifacts
|
||||
- a $1 dot epsilon$ softening is a good compromise between accuracy and stability
|
||||
]
|
||||
)
|
||||
|
||||
== N Body and variations
|
||||
sdsd
|
||||
|
||||
== Relaxation
|
||||
sd
|
||||
Relaxation [#link(<task1:compute_relaxation_time>)[code]]:
|
||||
// #helpers.code_cell(t1, "compute_relaxation_time")
|
||||
|
||||
|
||||
= Default Styling in diatypst
|
||||
Discussion!
|
||||
|
||||
== Terms, Code, Lists
|
||||
|
||||
_diatypst_ defines some default styling for elements, e.g Terms created with ```typc / Term: Definition``` will look like this
|
||||
|
||||
/ *Term*: Definition
|
||||
|
||||
A code block like this
|
||||
= Particle Mesh
|
||||
|
||||
```python
|
||||
// Example Code
|
||||
print("Hello World!")
|
||||
```
|
||||
|
||||
Lists have their marker respect the `title-color`
|
||||
|
||||
#columns(2)[
|
||||
- A
|
||||
- AAA
|
||||
- B
|
||||
#colbreak()
|
||||
1. AAA
|
||||
2. BBB
|
||||
3. CCC
|
||||
== Overview - the system
|
||||
#page(
|
||||
columns: 2
|
||||
)[
|
||||
#helpers.image_cell(t2, "plot_particle_distribution")
|
||||
]
|
||||
|
||||
|
||||
|
||||
== Force computation
|
||||
#helpers.code_reference_cell(t2, "function_mesh_force")
|
||||
|
||||
#helpers.image_cell(t2, "plot_force_radial")
|
||||
|
||||
#grid(
|
||||
columns: (2fr, 1fr),
|
||||
inset: 0.5em,
|
||||
block[
|
||||
#helpers.image_cell(t2, "plot_force_radial_single")
|
||||
// The radial force is computed as the sum of the forces of all particles in the system.
|
||||
#text(size: 0.6em)[
|
||||
$N^2$ force [#link(<task1:function_n2_forces>)[code]];
|
||||
$epsilon$ computation [#link(<task1:function_interparticle_distance>)[code]];
|
||||
Mesh force [#link(<task2:function_mesh_force>)[code]];
|
||||
]
|
||||
],
|
||||
block[
|
||||
Discussion:
|
||||
- using the (established) baseline of $N^2$ with $1 dot epsilon$ softening
|
||||
- small grids are stable but inaccurate at the center
|
||||
- very large grids have issues with overdiscretization
|
||||
|
||||
$==> 75 times 75 times 75$ as a good compromise
|
||||
]
|
||||
)
|
||||
|
||||
== Time integration
|
||||
=== Runge-Kutta
|
||||
#helpers.code_reference_cell(t2, "function_runge_kutta")
|
||||
|
||||
|
||||
#pagebreak()
|
||||
=== Results
|
||||
#align(center, block(
|
||||
height: 1fr,
|
||||
)[
|
||||
#helpers.image_cell(t2, "plot_system_evolution")
|
||||
])
|
||||
|
||||
|
||||
== Particle mesh solver
|
||||
sdlsd
|
||||
|
||||
|
||||
|
||||
|
||||
= Appendix - Code <appendix>
|
||||
|
||||
= Appendix - Code
|
||||
== Code
|
||||
#helpers.code_cell(t1, "plot_particle_distribution")
|
||||
<task1:plot_particle_distribution>
|
||||
#code_cell(t1, "plot_particle_distribution")
|
||||
|
||||
#pagebreak(weak: true)
|
||||
|
||||
#helpers.code_reference_cell(t1, "function_density_distribution")
|
||||
<task1:function_density_distribution>
|
||||
|
||||
#pagebreak(weak: true)
|
||||
|
||||
#helpers.code_reference_cell(t1, "function_analytical_forces")
|
||||
<task1:function_analytical_forces>
|
||||
|
||||
#pagebreak(weak: true)
|
||||
|
||||
#helpers.code_reference_cell(t1, "function_n2_forces")
|
||||
<task1:function_n2_forces>
|
||||
|
||||
#pagebreak(weak: true)
|
||||
|
||||
#helpers.code_reference_cell(t1, "function_interparticle_distance")
|
||||
<task1:function_interparticle_distance>
|
||||
|
||||
#pagebreak(weak: true)
|
||||
|
||||
#helpers.code_cell(t1, "compute_relaxation_time")
|
||||
<task1:compute_relaxation_time>
|
||||
|
||||
#pagebreak(weak: true)
|
||||
|
||||
#helpers.code_reference_cell(t2, "function_mesh_force")
|
||||
<task2:function_mesh_force>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#context {
|
||||
counter(page).update(locate(<appendix>).page())
|
||||
}
|
||||
|
Reference in New Issue
Block a user