diff --git a/doc/tutorials/constant_pH/constant_pH.ipynb b/doc/tutorials/constant_pH/constant_pH.ipynb
index e147a6c3bb7..8dabb3dc2b0 100644
--- a/doc/tutorials/constant_pH/constant_pH.ipynb
+++ b/doc/tutorials/constant_pH/constant_pH.ipynb
@@ -153,6 +153,7 @@
"import espressomd.electrostatics\n",
"import espressomd.reaction_methods\n",
"import espressomd.polymer\n",
+ "import espressomd.zn\n",
"from espressomd.interactions import HarmonicBond"
]
},
@@ -569,7 +570,7 @@
"\n",
"# add thermostat and short integration to let the system relax further\n",
"system.thermostat.set_langevin(kT=KT_REDUCED, gamma=1.0, seed=7)\n",
- "system.integrator.run(steps=1000)\n",
+ "system.integrator.run(1000)\n",
"\n",
"if USE_ELECTROSTATICS:\n",
" COULOMB_PREFACTOR=BJERRUM_LENGTH_REDUCED * KT_REDUCED\n",
@@ -739,6 +740,40 @@
"outputs": [],
"source": []
},
+ {
+ "cell_type": "markdown",
+ "id": "cd417295-bab3-46a5-a574-fc60d06371a5",
+ "metadata": {},
+ "source": [
+ "We will initialize the zndraw visualizer to visualize the simulation for increasing pH value:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "04dd303c",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "color = {TYPES[\"HA\"]: \"#7fc454\", #green\n",
+ " TYPES[\"A\"]: \"#225204\", #dark green\n",
+ " TYPES[\"B\"]: \"#fca000\", #orange\n",
+ " TYPES[\"Na\"]: \"#ff0000\", #red\n",
+ " TYPES[\"Cl\"]: \"#030ffc\" #blue\n",
+ " }\n",
+ "radii = {TYPES[\"HA\"]: 2,\n",
+ " TYPES[\"A\"]: 2,\n",
+ " TYPES[\"B\"]: 2,\n",
+ " TYPES[\"Na\"]: 2,\n",
+ " TYPES[\"Cl\"]: 2\n",
+ " }\n",
+ "\n",
+ "vis = espressomd.zn.Visualizer(system, colors=color, radii=radii)\n",
+ "vis.update()"
+ ]
+ },
{
"cell_type": "markdown",
"id": "07daa583",
@@ -778,11 +813,14 @@
"outputs": [],
"source": [
"# SOLUTION CELL\n",
- "def perform_sampling(type_A, num_samples, num_As:np.ndarray, reaction_steps, \n",
+ "def perform_sampling(type_A, num_samples, num_As:np.ndarray, reaction_steps,\n",
" prob_integration=0.5, integration_steps=1000):\n",
" for i in range(num_samples):\n",
" if USE_WCA and np.random.random() < prob_integration:\n",
- " system.integrator.run(integration_steps)\n",
+ " for _ in range(integration_steps):\n",
+ " system.integrator.run(1)\n",
+ " global vis\n",
+ " vis.update()\n",
" # we should do at least one reaction attempt per reactive particle\n",
" RE.reaction(steps=reaction_steps)\n",
" num_As[i] = system.number_of_particles(type=type_A)"
diff --git a/doc/tutorials/electrodes/electrodes_part2.ipynb b/doc/tutorials/electrodes/electrodes_part2.ipynb
index 4cae3ebcd54..1aaf34d86e7 100644
--- a/doc/tutorials/electrodes/electrodes_part2.ipynb
+++ b/doc/tutorials/electrodes/electrodes_part2.ipynb
@@ -214,6 +214,7 @@
"import espressomd.observables\n",
"import espressomd.accumulators\n",
"import espressomd.shapes\n",
+ "import espressomd.zn\n",
"\n",
"espressomd.assert_features(['WCA', 'ELECTROSTATICS'])\n",
"rng = np.random.default_rng(42)\n",
@@ -476,20 +477,20 @@
"source": [
"# SOLUTION CELL\n",
"offset = LJ_SIGMA # avoid unfavorable overlap at close distance to the walls\n",
- "init_part_btw_z1 = offset \n",
+ "init_part_btw_z1 = offset\n",
"init_part_btw_z2 = box_l_z - offset\n",
- "ion_pos = np.empty((3), dtype=float)\n",
+ "ion_pos = np.empty((3,), dtype=float)\n",
"\n",
- "for i in range (N_IONPAIRS):\n",
- " ion_pos[0] = rng.random(1) * system.box_l[0]\n",
- " ion_pos[1] = rng.random(1) * system.box_l[1]\n",
- " ion_pos[2] = rng.random(1) * (init_part_btw_z2 - init_part_btw_z1) + init_part_btw_z1\n",
+ "for i in range(N_IONPAIRS):\n",
+ " ion_pos[0] = rng.random(1)[0] * system.box_l[0]\n",
+ " ion_pos[1] = rng.random(1)[0] * system.box_l[1]\n",
+ " ion_pos[2] = rng.random(1)[0] * (init_part_btw_z2 - init_part_btw_z1) + init_part_btw_z1\n",
" system.part.add(pos=ion_pos, type=types[\"Cation\"], q=charges[\"Cation\"])\n",
- " \n",
- "for i in range (N_IONPAIRS):\n",
- " ion_pos[0] = rng.random(1) * system.box_l[0]\n",
- " ion_pos[1] = rng.random(1) * system.box_l[1]\n",
- " ion_pos[2] = rng.random(1) * (init_part_btw_z2 - init_part_btw_z1) + init_part_btw_z1\n",
+ "\n",
+ "for i in range(N_IONPAIRS):\n",
+ " ion_pos[0] = rng.random(1)[0] * system.box_l[0]\n",
+ " ion_pos[1] = rng.random(1)[0] * system.box_l[1]\n",
+ " ion_pos[2] = rng.random(1)[0] * (init_part_btw_z2 - init_part_btw_z1) + init_part_btw_z1\n",
" system.part.add(pos=ion_pos, type=types[\"Anion\"], q=charges[\"Anion\"])"
]
},
@@ -1008,7 +1009,40 @@
"\n",
"With the above knowledge, we can now assess the \n",
"differential capacitance of the system, by changing the applied voltage\n",
- "difference and determining the corresponding surface charge density."
+ "difference and determining the corresponding surface charge density.\n",
+ "We will use the ZnDraw visualizer to visualize our system:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ef5d908f-a7f0-4845-9555-34822128c141",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "color = {\n",
+ " types[\"Cation\"]: \"#ff0000\", #red\n",
+ " types[\"Anion\"]: \"#030ffc\" #blue\n",
+ " }\n",
+ " \n",
+ "radii = {\n",
+ " types[\"Cation\"]: LJ_SIGMA,\n",
+ " types[\"Anion\"]: LJ_SIGMA\n",
+ " }\n",
+ "\n",
+ "vis = espressomd.zn.Visualizer(system, colors=color, radii=radii)\n",
+ "#vis.draw_constraints([floor, ceiling])\n",
+ "\n",
+ "#note: The system displayed is the enlarged system as you can see the ELG-GAP along the nonperiodic direction. The particles are only in the smaller subsystem.\n",
+ "#note: The particles are shown bigger for visualization purpose."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "21da58e8-e666-4d06-8538-a8d6af521148",
+ "metadata": {},
+ "source": [
+ "Do the sampling from high to low potential:"
]
},
{
@@ -1029,7 +1063,9 @@
"for potential_diff in tqdm.tqdm(np.linspace(MIN_PHI, MAX_PHI, N_PHI)[::-1]):\n",
" system.auto_update_accumulators.clear()\n",
" system.electrostatics.solver = setup_electrostatic_solver(potential_diff)\n",
- " system.integrator.run(N_SAMPLES_EQUIL_CAP * STEPS_PER_SAMPLE)\n",
+ " for i in range(N_SAMPLES_EQUIL_CAP * STEPS_PER_SAMPLE//50):\n",
+ " system.integrator.run(50)\n",
+ " vis.update()\n",
" sigmas = []\n",
"\n",
" for tm in range(N_SAMPLES_CAP):\n",
@@ -1039,7 +1075,9 @@
" system.auto_update_accumulators.clear()\n",
" system.auto_update_accumulators.add(density_accumulator_cation)\n",
" system.auto_update_accumulators.add(density_accumulator_anion)\n",
- " system.integrator.run(STEPS_PER_SAMPLE)\n",
+ " for j in range(int(STEPS_PER_SAMPLE/50)):\n",
+ " system.integrator.run(50)\n",
+ " vis.update()\n",
"\n",
" cation_profile_mean = density_accumulator_cation.mean()[0, 0, :]\n",
" anion_profile_mean = density_accumulator_anion.mean()[0, 0, :]\n",
diff --git a/doc/tutorials/ferrofluid/ferrofluid_part1.ipynb b/doc/tutorials/ferrofluid/ferrofluid_part1.ipynb
index d65111cce28..2bd4d2ad56e 100644
--- a/doc/tutorials/ferrofluid/ferrofluid_part1.ipynb
+++ b/doc/tutorials/ferrofluid/ferrofluid_part1.ipynb
@@ -257,6 +257,7 @@
"import espressomd.magnetostatics\n",
"import espressomd.cluster_analysis\n",
"import espressomd.pair_criteria\n",
+ "import espressomd.zn\n",
"\n",
"espressomd.assert_features(['DIPOLES', 'DP3M', 'LENNARD_JONES'])\n",
"\n",
@@ -607,7 +608,7 @@
"id": "a6c4c46b",
"metadata": {},
"source": [
- "## Sampling"
+ "## Sampling and cluster analysis"
]
},
{
@@ -615,6 +616,8 @@
"id": "af0906f5",
"metadata": {},
"source": [
+ "To quantify the number of clusters and their respective sizes, we now want to perform a cluster analysis.\n",
+ "For that we can use ESPREsSo's [cluster analysis class](https://espressomd.github.io/doc/analysis.html?highlight=cluster%20analysis#cluster-analysis).\n",
"The system will be sampled over 100 loops."
]
},
@@ -628,159 +631,6 @@
"LOOPS = 100"
]
},
- {
- "cell_type": "markdown",
- "id": "516c2f33",
- "metadata": {},
- "source": [
- "As the system is two dimensional, we can simply do a scatter plot to get a visual representation of a system state. To get a better insight of how a ferrofluid system develops during time we will create a video of the development of our system during the sampling. If you only want to sample the system simply go to [Sampling without animation](#Sampling-without-animation)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "60dc1653",
- "metadata": {},
- "source": [
- "### Sampling with animation"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5f7fe3a7",
- "metadata": {},
- "source": [
- "To get an animation of the system development we have to create a function which will save the video and embed it in an html string."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ed0ee691",
- "metadata": {},
- "outputs": [],
- "source": [
- "import matplotlib.animation as animation\n",
- "import tempfile\n",
- "import base64\n",
- "\n",
- "VIDEO_TAG = \"\"\"\"\"\"\n",
- "\n",
- "\n",
- "def anim_to_html(anim):\n",
- " if not hasattr(anim, '_encoded_video'):\n",
- " with tempfile.NamedTemporaryFile(suffix='.mp4') as f:\n",
- " anim.save(f.name, fps=20, extra_args=['-vcodec', 'libx264'])\n",
- " with open(f.name, \"rb\") as g:\n",
- " video = g.read()\n",
- " anim._encoded_video = base64.b64encode(video).decode('ascii')\n",
- " plt.close(anim._fig)\n",
- " return VIDEO_TAG.format(anim._encoded_video)\n",
- "\n",
- "\n",
- "animation.Animation._repr_html_ = anim_to_html\n",
- "\n",
- "\n",
- "def init():\n",
- " # Set x and y range\n",
- " ax.set_ylim(0, BOX_SIZE)\n",
- " ax.set_xlim(0, BOX_SIZE)\n",
- " x_data, y_data = [], []\n",
- " part.set_data(x_data, y_data)\n",
- " return part,"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "89d9844a",
- "metadata": {},
- "source": [
- "## Exercise:\n",
- "\n",
- "In the following an animation loop is defined, however it is incomplete.\n",
- "Extend the code such that in every loop the system is integrated for 100 steps.\n",
- "Afterwards `x_data` and `y_data` have to be populated by the folded $x$- and $y$- positions of the particles.\n",
- "\n",
- "(You may copy and paste the incomplete code template to the empty cell below.)\n",
- "\n",
- "```python\n",
- "def run(i):\n",
- " # < excercise >\n",
- " \n",
- " # Save current system state as a plot\n",
- " x_data, y_data = # < excercise >\n",
- " ax.figure.canvas.draw()\n",
- " part.set_data(x_data, y_data)\n",
- " print(f'progress: {(i + 1) * 100. / LOOPS:3.0f}%', end='\\r')\n",
- " return part,\n",
- "```"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "91004d62",
- "metadata": {},
- "outputs": [],
- "source": [
- "# SOLUTION CELL\n",
- "def run(i):\n",
- " system.integrator.run(100)\n",
- "\n",
- " # Save current system state as a plot\n",
- " x_data, y_data = system.part.all().pos_folded[:, 0], system.part.all().pos_folded[:, 1]\n",
- " ax.figure.canvas.draw()\n",
- " part.set_data(x_data, y_data)\n",
- " print(f'progress: {(i + 1) * 100. / LOOPS:3.0f}%', end='\\r')\n",
- " return part,"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "95caca0c",
- "metadata": {},
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "markdown",
- "id": "0f7e9093",
- "metadata": {},
- "source": [
- "Now we use the animation class of matplotlib to save snapshots of the system as frames of a video which is then displayed after the sampling is finished. Between two frames are 100 integration steps.\n",
- "\n",
- "In the video chain-like and ring-like clusters should be visible, as well as some isolated monomers."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "3d11e830",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "fig, ax = plt.subplots(figsize=(10, 10))\n",
- "part, = ax.plot([], [], 'o')\n",
- "\n",
- "animation.FuncAnimation(fig, run, frames=LOOPS, blit=True, interval=0, repeat=False, init_func=init)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a7ab793c",
- "metadata": {},
- "source": [
- "## Cluster analysis\n",
- "\n",
- "To quantify the number of clusters and their respective sizes, we now want to perform a cluster analysis.\n",
- "For that we can use ESPREsSo's [cluster analysis class](https://espressomd.github.io/doc/analysis.html?highlight=cluster%20analysis#cluster-analysis)."
- ]
- },
{
"cell_type": "markdown",
"id": "2f6d201a",
@@ -847,15 +697,19 @@
"id": "6b8d8e7f",
"metadata": {},
"source": [
- "### Sampling without animation"
+ "We initialize an instance of the ZnDraw visualizer to animate the sampling. As our system is constrained to 2D, the particles are on a single face of the cubic system box."
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
"id": "2098e033",
+ "execution_count": null,
"metadata": {},
+ "outputs": [],
"source": [
- "The following code just samples the system and does a cluster analysis every loops (100 by default) simulation steps."
+ "color = {0: \"#7fc454\"} \n",
+ "radii = {0: LJ_SIGMA/2}\n",
+ "vis = espressomd.zn.Visualizer(system, colors=color, radii=radii)"
]
},
{
@@ -878,6 +732,7 @@
" for c in cluster_structure.clusters:\n",
" cluster_sizes.append(# < excercise >)\n",
" system.integrator.run(100)\n",
+ " vis.update()\n",
"```"
]
},
@@ -899,7 +754,8 @@
" n_clusters.append(len(cluster_structure.clusters))\n",
" for c in cluster_structure.clusters:\n",
" cluster_sizes.append(c[1].size())\n",
- " system.integrator.run(100)"
+ " system.integrator.run(100)\n",
+ " vis.update()"
]
},
{
@@ -915,7 +771,7 @@
"id": "0042827e",
"metadata": {},
"source": [
- "You may want to get a visualization of the current state of the system. For that we plot the particle positions folded to the simulation box using matplotlib."
+ "You may want to get a 2D visualization of the current state of the system. For that we plot the particle positions folded to the simulation box using matplotlib."
]
},
{
diff --git a/doc/tutorials/ferrofluid/ferrofluid_part2.ipynb b/doc/tutorials/ferrofluid/ferrofluid_part2.ipynb
index 453d5f9e979..e13eb759f96 100644
--- a/doc/tutorials/ferrofluid/ferrofluid_part2.ipynb
+++ b/doc/tutorials/ferrofluid/ferrofluid_part2.ipynb
@@ -59,6 +59,7 @@
"source": [
"import espressomd\n",
"import espressomd.magnetostatics\n",
+ "import espressomd.zn\n",
"\n",
"espressomd.assert_features(['DIPOLES', 'DP3M', 'LENNARD_JONES'])\n",
"\n",
@@ -305,95 +306,27 @@
"plt.show()"
]
},
- {
- "cell_type": "markdown",
- "id": "2f52d782",
- "metadata": {},
- "source": [
- "## Video of the development of the system"
- ]
- },
{
"cell_type": "markdown",
"id": "eb06ab55",
"metadata": {},
"source": [
- "You may want to get an insight of how the system develops in time. Thus we now create a function which will save a video and embed it in an html string to create a video of the systems development "
+ "You may want to get an insight of how the system develops in time. We use the ZnDraw visualiser:"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "e25ba03b",
+ "id": "a6807ebd-2f97-476c-94e1-ea5fe1d383a4",
"metadata": {},
"outputs": [],
"source": [
- "import matplotlib.pyplot as plt\n",
- "import matplotlib.animation as animation\n",
- "import tempfile\n",
- "import base64\n",
- "\n",
- "VIDEO_TAG = \"\"\"\"\"\"\n",
- "\n",
- "\n",
- "def anim_to_html(anim):\n",
- " if not hasattr(anim, '_encoded_video'):\n",
- " with tempfile.NamedTemporaryFile(suffix='.mp4') as f:\n",
- " anim.save(f.name, fps=20, extra_args=['-vcodec', 'libx264'])\n",
- " with open(f.name, \"rb\") as g:\n",
- " video = g.read()\n",
- " anim._encoded_video = base64.b64encode(video).decode('ascii')\n",
- " plt.close(anim._fig)\n",
- " return VIDEO_TAG.format(anim._encoded_video)\n",
- "\n",
- "\n",
- "animation.Animation._repr_html_ = anim_to_html\n",
- "\n",
- "\n",
- "def init():\n",
- " # Set x and y range\n",
- " ax.set_ylim(0, box_size)\n",
- " ax.set_xlim(0, box_size)\n",
- " xdata, ydata = [], []\n",
- " part.set_data(xdata, ydata)\n",
- " return part,\n",
- "\n",
- "\n",
- "def run(i):\n",
+ "color = {0: \"#7fc454\"} \n",
+ "radii = {0: LJ_SIGMA/2}\n",
+ "vis = espressomd.zn.Visualizer(system, colors=color, radii=radii)\n",
+ "for _ in range(100):\n",
" system.integrator.run(50)\n",
- "\n",
- " # Save current system state as a plot\n",
- " xdata, ydata = particles.pos_folded[:, 0], particles.pos_folded[:, 1]\n",
- " ax.figure.canvas.draw()\n",
- " part.set_data(xdata, ydata)\n",
- " print(f'progress: {(i + 1):3.0f}%', end='\\r')\n",
- " return part,"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "25b6af88",
- "metadata": {},
- "source": [
- "We now can start the sampling over the animation class of matplotlib"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "8c9fe146",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "fig, ax = plt.subplots(figsize=(10, 10))\n",
- "part, = ax.plot([], [], 'o')\n",
- "\n",
- "animation.FuncAnimation(fig, run, frames=100, blit=True, interval=0, repeat=False, init_func=init)"
+ " vis.update()"
]
},
{
@@ -401,7 +334,7 @@
"id": "278cfc7f",
"metadata": {},
"source": [
- "In the visualization video we can see that the single chains break and connect to each other during time. Also some monomers are present which break from and connect to chains. If you want to have some more frames, i.e. a longer video, just adjust the frames parameter in FuncAnimation."
+ "In the visualization video we can see that the single chains break and connect to each other during time. Also some monomers are present which break from and connect to chains."
]
},
{
diff --git a/doc/tutorials/ferrofluid/ferrofluid_part3.ipynb b/doc/tutorials/ferrofluid/ferrofluid_part3.ipynb
index b7f896f46a6..8bce1733db3 100644
--- a/doc/tutorials/ferrofluid/ferrofluid_part3.ipynb
+++ b/doc/tutorials/ferrofluid/ferrofluid_part3.ipynb
@@ -134,6 +134,7 @@
"source": [
"import espressomd\n",
"import espressomd.magnetostatics\n",
+ "import espressomd.zn\n",
"\n",
"espressomd.assert_features(['DIPOLES', 'DP3M', 'LENNARD_JONES'])\n",
"\n",
@@ -536,6 +537,14 @@
"As in **part II** we use the same system for every value of the Langevin parameter $\\alpha$. Thus we use that the system is already pre-equilibrated from the previous run so we save some equilibration time. For scientific purposes one would use a new system for every value for the Langevin parameter to ensure that the systems are independent and no correlation effects are measured. Also one would perform more than just one simulation for each value of $\\alpha$ to increase the precision of the results."
]
},
+ {
+ "cell_type": "markdown",
+ "id": "395a4fc0-baaf-48d6-8b88-b8ba42408bfe",
+ "metadata": {},
+ "source": [
+ "Additionally, we will visualize the sampling of the magnetization curve using the ZnDraw visualizer. Note, that the magnetic field is increasing during the video."
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
@@ -579,7 +588,8 @@
" magnetizations[ndx] = np.mean(magn_temp)\n",
"\n",
" # remove constraint\n",
- " system.constraints.clear()"
+ " if not alpha == alphas[-1]:\n",
+ " system.constraints.clear()"
]
},
{
@@ -668,6 +678,39 @@
"At sufficiently high volume fractions $\\phi$ and dipolar interaction parameters $\\lambda$ these clusters can be so rigid, that simulations with normal methods are impossible as the relaxation times exceeds normal simulation times by far, resulting in strongly correlated configurations and thus measurements."
]
},
+ {
+ "cell_type": "markdown",
+ "id": "d2333fe6-c427-48b6-92f0-d946f4084b30",
+ "metadata": {},
+ "source": [
+ "## Visualization"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7fd720f4-858e-4d2e-8d4a-23644ab996e3",
+ "metadata": {},
+ "source": [
+ "Finally, we use ZnDraw to visualize the evolving system for high $\\alpha$. We just need to continue running our system as it is already warmed up for high magnetic field."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8e1d8ade-efa9-4d73-a328-27b0e63993b4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# initializing zndraw visualizer\n",
+ "color = {0: \"#7fc454\"} \n",
+ "radii = {0: lj_sigma/2}\n",
+ "vis = espressomd.zn.Visualizer(system, colors=color, radii=radii)\n",
+ "\n",
+ "for _ in range(400):\n",
+ " system.integrator.run(5)\n",
+ " vis.update()"
+ ]
+ },
{
"cell_type": "markdown",
"id": "81e06b9b",
diff --git a/doc/tutorials/langevin_dynamics/langevin_dynamics.ipynb b/doc/tutorials/langevin_dynamics/langevin_dynamics.ipynb
index 804725d1799..5f6471c40bb 100644
--- a/doc/tutorials/langevin_dynamics/langevin_dynamics.ipynb
+++ b/doc/tutorials/langevin_dynamics/langevin_dynamics.ipynb
@@ -159,14 +159,6 @@
"## 2. Simulating Brownian motion"
]
},
- {
- "cell_type": "markdown",
- "id": "c38456fa",
- "metadata": {},
- "source": [
- "We will simulate the diffusion of a single particle that is coupled to an implicit solvent."
- ]
- },
{
"cell_type": "code",
"execution_count": null,
@@ -181,6 +173,7 @@
"import espressomd\n",
"import espressomd.accumulators\n",
"import espressomd.observables\n",
+ "import espressomd.zn\n",
"\n",
"logging.basicConfig(level=logging.INFO, stream=sys.stdout)\n",
"\n",
@@ -188,15 +181,76 @@
"KT = 1.1\n",
"STEPS = 1000000\n",
"\n",
+ "gammas = [1.0, 2.0, 4.0, 10.0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c38456fa",
+ "metadata": {},
+ "source": [
+ "We will simulate the diffusion of a single particle that is coupled to an implicit solvent. First, we have to setup our system."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "45a6ad79-fae4-4bd7-b041-012b193b83bf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
"# System setup\n",
"system = espressomd.System(box_l=[16] * 3)\n",
"system.time_step = 0.01\n",
"system.cell_system.skin = 0.4\n",
"\n",
- "particle = system.part.add(pos=[0, 0, 0])\n",
+ "particle = system.part.add(pos=[0, 0, 0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3d594176-bd64-4ce8-9e25-f0efefbf996c",
+ "metadata": {},
+ "source": [
+ "In order to get an idea of the Brownian motion, we will visualize our system evolving for a few steps with the ZnDraw visualizer:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "80788a7f-4bf2-4fa6-9292-5de8b2a926ff",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "system.thermostat.set_langevin(kT=KT, gamma=gammas[0], seed=42)\n",
"\n",
+ "# Setup ZnDraw visualizer\n",
+ "color = {0: \"#7fc454\"} \n",
+ "radii = {0: 1}\n",
+ "vis = espressomd.zn.Visualizer(system, colors=color, radii=radii)\n",
+ "\n",
+ "system.integrator.run(1000)\n",
+ "for _ in range(200):\n",
+ " system.integrator.run(50)\n",
+ " vis.update()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "933cea77-4bca-47a6-8a82-cc13d07ec673",
+ "metadata": {},
+ "source": [
+ "Now we can do the actual simulation where we simulate for different friction coefficients and sample our observables:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bf997a0a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
"# Run for different friction coefficients\n",
- "gammas = [1.0, 2.0, 4.0, 10.0]\n",
"tau_results = []\n",
"msd_results = []\n",
"vacf_results = []\n",
diff --git a/doc/tutorials/raspberry_electrophoresis/raspberry_electrophoresis.ipynb b/doc/tutorials/raspberry_electrophoresis/raspberry_electrophoresis.ipynb
index 1d914418550..a72c35294e7 100644
--- a/doc/tutorials/raspberry_electrophoresis/raspberry_electrophoresis.ipynb
+++ b/doc/tutorials/raspberry_electrophoresis/raspberry_electrophoresis.ipynb
@@ -71,6 +71,7 @@
"import espressomd.interactions\n",
"import espressomd.electrostatics\n",
"import espressomd.lb\n",
+ "import espressomd.zn\n",
"\n",
"import sys\n",
"import tqdm\n",
@@ -683,6 +684,56 @@
"system.thermostat.set_lb(LB_fluid=lb, seed=123, gamma=20.0)"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "a7388457-8c1b-4839-bfc6-e34778ae9511",
+ "metadata": {},
+ "source": [
+ "## Visualization"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f3deb299-de31-4901-8f65-0ff06112232c",
+ "metadata": {},
+ "source": [
+ "We use the ZnDraw visualizer and run our simulation for a few steps in order to get an idea what is happening in our system:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c24f4ee4-2a6a-46ff-ba89-4f6c7f7fb227",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Initializing ZnDraw visualizer\n",
+ "colors = {\n",
+ " TYPE_CENTRAL: \"#fca000\", #orange\n",
+ " TYPE_SURFACE: \"#7fc454\", #green\n",
+ " TYPE_CATIONS: \"#ff0000\", #red\n",
+ " TYPE_ANIONS: \"#030ffc\" #blue\n",
+ " }\n",
+ "radii = {\n",
+ " TYPE_CENTRAL: sig_ss/2,\n",
+ " TYPE_SURFACE: sig_ss/2,\n",
+ " TYPE_CATIONS: sig_ss/2,\n",
+ " TYPE_ANIONS: sig_ss/2\n",
+ " }\n",
+ "arrows_config = {'colormap': [[-0.5, 0.9, 0.5], [-0.0, 0.9, 0.5]],\n",
+ " 'normalize': True,\n",
+ " 'colorrange': [0, 1],\n",
+ " 'scale_vector_thickness': True,\n",
+ " 'opacity': 1.0}\n",
+ "\n",
+ "lbfield = espressomd.zn.LBField(system, step_x=2, step_y=2, step_z=5, scale=0.3)\n",
+ "vis = espressomd.zn.Visualizer(system, colors=colors, radii=radii, folded=True, vector_field=lbfield)\n",
+ "\n",
+ "for _ in range(50):\n",
+ " system.integrator.run(10)\n",
+ " vis.update()"
+ ]
+ },
{
"cell_type": "markdown",
"id": "f848c501",
@@ -709,6 +760,7 @@
"with open('posVsTime.dat', 'w') as f: # file where the raspberry trajectory will be written to\n",
" for _ in tqdm.tqdm(range(num_iterations)):\n",
" system.integrator.run(num_steps_per_iteration)\n",
+ " vis.update()\n",
" pos = central_part.pos - initial_pos\n",
" f.write(f\"{system.time:.2f} {pos[0]:.4f} {pos[1]:.4f} {pos[2]:.4f}\\n\")\n",
"\n",