From d0f9d1b07ed31dedafec07be794cf90701556ad2 Mon Sep 17 00:00:00 2001 From: olastrz Date: Mon, 11 Aug 2025 19:08:47 +0200 Subject: [PATCH 01/29] New notebook for Pyrcel in pyeVTK. --- examples/PySDM_examples/Pyrcel/paraview.ipynb | 787 ++++++++++++++++++ 1 file changed, 787 insertions(+) create mode 100644 examples/PySDM_examples/Pyrcel/paraview.ipynb diff --git a/examples/PySDM_examples/Pyrcel/paraview.ipynb b/examples/PySDM_examples/Pyrcel/paraview.ipynb new file mode 100644 index 000000000..81fcce9dc --- /dev/null +++ b/examples/PySDM_examples/Pyrcel/paraview.ipynb @@ -0,0 +1,787 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 9, + "id": "6dcbcc6d", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from PySDM import Formulae\n", + "from PySDM.physics import si\n", + "from PySDM.initialisation.spectra import Lognormal\n", + "from PySDM.products import (\n", + " ParcelDisplacement, AmbientTemperature, AmbientDryAirDensity, AmbientRelativeHumidity,\n", + " ParticleSizeSpectrumPerVolume, ParticleVolumeVersusRadiusLogarithmSpectrum\n", + ")\n", + "\n", + "from PySDM_examples.Pyrcel import Settings, Simulation" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "id": "cd6288b5", + "metadata": {}, + "outputs": [], + "source": [ + "settings = Settings(\n", + " dz = 10 * si.m,\n", + " n_sd_per_mode = (1, 1),\n", + " aerosol_modes_by_kappa = {\n", + " .54: Lognormal(\n", + " norm_factor=850 / si.cm ** 3,\n", + " m_mode=15 * si.nm,\n", + " s_geom=1.6\n", + " ),\n", + " 1.2: Lognormal(\n", + " norm_factor=10 / si.cm ** 3,\n", + " m_mode=850 * si.nm,\n", + " s_geom=1.2\n", + " )\n", + " },\n", + " vertical_velocity = 1.0 * si.m / si.s,\n", + " initial_pressure = 775 * si.mbar,\n", + " initial_temperature = 274 * si.K,\n", + " initial_relative_humidity = .98,\n", + " displacement = 1000 * si.m,\n", + " formulae = Formulae(constants={'MAC': .3})\n", + ")\n", + "\n", + "dry_radius_bin_edges = np.logspace(\n", + " np.log10(1e-3 * si.um),\n", + " np.log10(5e0 * si.um),\n", + " 33, endpoint=False\n", + ")\n", + "\n", + "simulation = Simulation(settings, products=(\n", + " ParcelDisplacement(\n", + " name='z'),\n", + " AmbientRelativeHumidity(\n", + " name='S_max_percent', unit='%', var='RH'),\n", + " AmbientTemperature(\n", + " name='T'),\n", + " ParticleSizeSpectrumPerVolume(\n", + " name='dry:dN/dR', radius_bins_edges=dry_radius_bin_edges, dry=True),\n", + " ParticleVolumeVersusRadiusLogarithmSpectrum(\n", + " name='dry:dV/dlnR', radius_bins_edges=dry_radius_bin_edges, dry=True),\n", + " AmbientDryAirDensity(),\n", + "))" + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "id": "3ff50a25", + "metadata": {}, + "outputs": [], + "source": [ + "output = simulation.run()" + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "id": "d645954c", + "metadata": {}, + "outputs": [], + "source": [ + "from pyevtk.hl import unstructuredGridToVTK, pointsToVTK\n", + "from pyevtk.vtk import VtkHexahedron, VtkGroup\n", + "import numpy as np\n", + "\n", + "from PySDM.exporters import VTKExporter\n", + "\n", + "\n", + "class VTKExporterParcel(VTKExporter):\n", + " def __init__(self, n_sd):\n", + " super().__init__()\n", + " self.x = np.random.random(n_sd)\n", + " self.y = np.random.random(n_sd)\n", + " self.z = np.random.random(n_sd)\n", + "\n", + " def write_pvd(self):\n", + " pvd_attributes = VtkGroup(self.attributes_file_path)\n", + " for k, v in self.exported_times[\"attributes\"].items():\n", + " pvd_attributes.addFile(k + \".vtu\", sim_time=v)\n", + " pvd_attributes.save()\n", + "\n", + " pvd_products = VtkGroup(self.products_file_path)\n", + " for k, v in self.exported_times[\"products\"].items():\n", + " pvd_products.addFile(k + \".vtu\", sim_time=v)\n", + " pvd_products.save()\n", + "\n", + " def export_products(self, output, step):\n", + " path = (\n", + " self.products_file_path\n", + " + \"_num\"\n", + " + self.add_leading_zeros(step)\n", + " )\n", + " print(path)\n", + " self.exported_times[\"products\"][path] = (\n", + " step * simulation.particulator.dt\n", + " )\n", + "\n", + " n_levels = len(output['products']['z'])\n", + " n_vertices = 4 * n_levels\n", + " x = np.zeros(n_vertices)\n", + " y = np.zeros(n_vertices)\n", + " z = np.zeros(n_vertices)\n", + " conn = [0, 1, 2, 3]\n", + " ctype = np.zeros(n_levels - 1)\n", + " ctype[:] = VtkHexahedron.tid\n", + "\n", + " _volume = simulation.particulator.environment.mass_of_dry_air / output['products']['rhod'][0]\n", + " _dz = output['products']['z'][1] - output['products']['z'][0]\n", + " for level in range(n_levels): \n", + " _z = output['products']['z'][level] \n", + " if level > 0:\n", + " prev_to_curr_density_ratio = output['products']['rhod'][level-1] / output['products']['rhod'][level]\n", + " _volume *= prev_to_curr_density_ratio\n", + " _dz = output['products']['z'][level] - output['products']['z'][level-1]\n", + " _area = _volume / _dz\n", + " _half_diagonal = (2 * _area) ** .5\n", + " x[i := level * 4], y[i], z[i] = -_half_diagonal, -_half_diagonal, _z \n", + " x[i := i + 1], y[i], z[i] = -_half_diagonal, _half_diagonal, _z\n", + " x[i := i + 1], y[i], z[i] = _half_diagonal, _half_diagonal, _z\n", + " x[i := i + 1], y[i], z[i] = _half_diagonal, -_half_diagonal, _z\n", + " conn += [*range(4 * (level + 1), 4 * (level + 2))] * 2\n", + " conn = np.asarray(conn[:-4])\n", + " offset = np.asarray(range(8, 8 * n_levels, 8))\n", + "\n", + " point_data = {\"test_pd\": np.array([44] * n_vertices)}\n", + "\n", + " _RH = output['products']['S_max_percent']\n", + " cell_data = {\"RH\": np.full(shape=(len(_RH)-1,), fill_value=np.nan)}\n", + " cell_data[\"RH\"][:step] = (np.array(_RH[:-1] + np.diff(_RH)/2))[:step]\n", + " unstructuredGridToVTK(\n", + " path,\n", + " x,\n", + " y,\n", + " z,\n", + " connectivity=conn,\n", + " offsets=offset,\n", + " cell_types=ctype,\n", + " cellData=cell_data,\n", + " #pointData=point_data,\n", + " #fieldData=field_data,\n", + " )\n", + "\n", + " def export_attributes(self, output, step):\n", + " path = (\n", + " self.attributes_file_path\n", + " + \"_num\"\n", + " + self.add_leading_zeros(step)\n", + " )\n", + " self.exported_times[\"attributes\"][path] = step * simulation.particulator.dt\n", + " print(path)\n", + " payload = {}\n", + "\n", + " for k in output[\"attributes\"].keys():\n", + " payload[k] = np.asarray(output[\"attributes\"][k])[:,step].copy()\n", + "\n", + " if step != 0:\n", + " dz = output['products']['z'][step] - output['products']['z'][step - 1] \n", + " if step == 1:\n", + " self.z *= dz\n", + " else:\n", + " self.z += dz\n", + " print(self.z)\n", + "\n", + " pointsToVTK(path, self.x, self.y, self.z, data=payload)" + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "id": "15d59657", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ".\\output\\sd_products_num0000000000\n", + ".\\output\\sd_attributes_num0000000000\n", + "[0.46144518 0.47033488]\n", + ".\\output\\sd_products_num0000000001\n", + ".\\output\\sd_attributes_num0000000001\n", + "[4.61445177 4.70334881]\n", + ".\\output\\sd_products_num0000000002\n", + ".\\output\\sd_attributes_num0000000002\n", + "[14.61445177 14.70334881]\n", + ".\\output\\sd_products_num0000000003\n", + ".\\output\\sd_attributes_num0000000003\n", + "[24.61445177 24.70334881]\n", + ".\\output\\sd_products_num0000000004\n", + ".\\output\\sd_attributes_num0000000004\n", + "[34.61445177 34.70334881]\n", + ".\\output\\sd_products_num0000000005\n", + ".\\output\\sd_attributes_num0000000005\n", + "[44.61445177 44.70334881]\n", + ".\\output\\sd_products_num0000000006\n", + ".\\output\\sd_attributes_num0000000006\n", + "[54.61445177 54.70334881]\n", + ".\\output\\sd_products_num0000000007\n", + ".\\output\\sd_attributes_num0000000007\n", + "[64.61445177 64.70334881]\n", + ".\\output\\sd_products_num0000000008\n", + ".\\output\\sd_attributes_num0000000008\n", + "[74.61445177 74.70334881]\n", + ".\\output\\sd_products_num0000000009\n", + ".\\output\\sd_attributes_num0000000009\n", + "[84.61445177 84.70334881]\n", + ".\\output\\sd_products_num0000000010\n", + ".\\output\\sd_attributes_num0000000010\n", + "[94.61445177 94.70334881]\n", + ".\\output\\sd_products_num0000000011\n", + ".\\output\\sd_attributes_num0000000011\n", + "[104.61445177 104.70334881]\n", + ".\\output\\sd_products_num0000000012\n", + ".\\output\\sd_attributes_num0000000012\n", + "[114.61445177 114.70334881]\n", + ".\\output\\sd_products_num0000000013\n", + ".\\output\\sd_attributes_num0000000013\n", + "[124.61445177 124.70334881]\n", + ".\\output\\sd_products_num0000000014\n", + ".\\output\\sd_attributes_num0000000014\n", + "[134.61445177 134.70334881]\n", + ".\\output\\sd_products_num0000000015\n", + ".\\output\\sd_attributes_num0000000015\n", + "[144.61445177 144.70334881]\n", + ".\\output\\sd_products_num0000000016\n", + ".\\output\\sd_attributes_num0000000016\n", + "[154.61445177 154.70334881]\n", + ".\\output\\sd_products_num0000000017\n", + ".\\output\\sd_attributes_num0000000017\n", + "[164.61445177 164.70334881]\n", + ".\\output\\sd_products_num0000000018\n", + ".\\output\\sd_attributes_num0000000018\n", + "[174.61445177 174.70334881]\n", + ".\\output\\sd_products_num0000000019\n", + ".\\output\\sd_attributes_num0000000019\n", + "[184.61445177 184.70334881]\n", + ".\\output\\sd_products_num0000000020\n", + ".\\output\\sd_attributes_num0000000020\n", + "[194.61445177 194.70334881]\n", + ".\\output\\sd_products_num0000000021\n", + ".\\output\\sd_attributes_num0000000021\n", + "[204.61445177 204.70334881]\n", + ".\\output\\sd_products_num0000000022\n", + ".\\output\\sd_attributes_num0000000022\n", + "[214.61445177 214.70334881]\n", + ".\\output\\sd_products_num0000000023\n", + ".\\output\\sd_attributes_num0000000023\n", + "[224.61445177 224.70334881]\n", + ".\\output\\sd_products_num0000000024\n", + ".\\output\\sd_attributes_num0000000024\n", + "[234.61445177 234.70334881]\n", + ".\\output\\sd_products_num0000000025\n", + ".\\output\\sd_attributes_num0000000025\n", + "[244.61445177 244.70334881]\n", + ".\\output\\sd_products_num0000000026\n", + ".\\output\\sd_attributes_num0000000026\n", + "[254.61445177 254.70334881]\n", + ".\\output\\sd_products_num0000000027\n", + ".\\output\\sd_attributes_num0000000027\n", + "[264.61445177 264.70334881]\n", + ".\\output\\sd_products_num0000000028\n", + ".\\output\\sd_attributes_num0000000028\n", + "[274.61445177 274.70334881]\n", + ".\\output\\sd_products_num0000000029\n", + ".\\output\\sd_attributes_num0000000029\n", + "[284.61445177 284.70334881]\n", + ".\\output\\sd_products_num0000000030\n", + ".\\output\\sd_attributes_num0000000030\n", + "[294.61445177 294.70334881]\n", + ".\\output\\sd_products_num0000000031\n", + ".\\output\\sd_attributes_num0000000031\n", + "[304.61445177 304.70334881]\n", + ".\\output\\sd_products_num0000000032\n", + ".\\output\\sd_attributes_num0000000032\n", + "[314.61445177 314.70334881]\n", + ".\\output\\sd_products_num0000000033\n", + ".\\output\\sd_attributes_num0000000033\n", + "[324.61445177 324.70334881]\n", + ".\\output\\sd_products_num0000000034\n", + ".\\output\\sd_attributes_num0000000034\n", + "[334.61445177 334.70334881]\n", + ".\\output\\sd_products_num0000000035\n", + ".\\output\\sd_attributes_num0000000035\n", + "[344.61445177 344.70334881]\n", + ".\\output\\sd_products_num0000000036\n", + ".\\output\\sd_attributes_num0000000036\n", + "[354.61445177 354.70334881]\n", + ".\\output\\sd_products_num0000000037\n", + ".\\output\\sd_attributes_num0000000037\n", + "[364.61445177 364.70334881]\n", + ".\\output\\sd_products_num0000000038\n", + ".\\output\\sd_attributes_num0000000038\n", + "[374.61445177 374.70334881]\n", + ".\\output\\sd_products_num0000000039\n", + ".\\output\\sd_attributes_num0000000039\n", + "[384.61445177 384.70334881]\n", + ".\\output\\sd_products_num0000000040\n", + ".\\output\\sd_attributes_num0000000040\n", + "[394.61445177 394.70334881]\n", + ".\\output\\sd_products_num0000000041\n", + ".\\output\\sd_attributes_num0000000041\n", + "[404.61445177 404.70334881]\n", + ".\\output\\sd_products_num0000000042\n", + ".\\output\\sd_attributes_num0000000042\n", + "[414.61445177 414.70334881]\n", + ".\\output\\sd_products_num0000000043\n", + ".\\output\\sd_attributes_num0000000043\n", + "[424.61445177 424.70334881]\n", + ".\\output\\sd_products_num0000000044\n", + ".\\output\\sd_attributes_num0000000044\n", + "[434.61445177 434.70334881]\n", + ".\\output\\sd_products_num0000000045\n", + ".\\output\\sd_attributes_num0000000045\n", + "[444.61445177 444.70334881]\n", + ".\\output\\sd_products_num0000000046\n", + ".\\output\\sd_attributes_num0000000046\n", + "[454.61445177 454.70334881]\n", + ".\\output\\sd_products_num0000000047\n", + ".\\output\\sd_attributes_num0000000047\n", + "[464.61445177 464.70334881]\n", + ".\\output\\sd_products_num0000000048\n", + ".\\output\\sd_attributes_num0000000048\n", + "[474.61445177 474.70334881]\n", + ".\\output\\sd_products_num0000000049\n", + ".\\output\\sd_attributes_num0000000049\n", + "[484.61445177 484.70334881]\n", + ".\\output\\sd_products_num0000000050\n", + ".\\output\\sd_attributes_num0000000050\n", + "[494.61445177 494.70334881]\n", + ".\\output\\sd_products_num0000000051\n", + ".\\output\\sd_attributes_num0000000051\n", + "[504.61445177 504.70334881]\n", + ".\\output\\sd_products_num0000000052\n", + ".\\output\\sd_attributes_num0000000052\n", + "[514.61445177 514.70334881]\n", + ".\\output\\sd_products_num0000000053\n", + ".\\output\\sd_attributes_num0000000053\n", + "[524.61445177 524.70334881]\n", + ".\\output\\sd_products_num0000000054\n", + ".\\output\\sd_attributes_num0000000054\n", + "[534.61445177 534.70334881]\n", + ".\\output\\sd_products_num0000000055\n", + ".\\output\\sd_attributes_num0000000055\n", + "[544.61445177 544.70334881]\n", + ".\\output\\sd_products_num0000000056\n", + ".\\output\\sd_attributes_num0000000056\n", + "[554.61445177 554.70334881]\n", + ".\\output\\sd_products_num0000000057\n", + ".\\output\\sd_attributes_num0000000057\n", + "[564.61445177 564.70334881]\n", + ".\\output\\sd_products_num0000000058\n", + ".\\output\\sd_attributes_num0000000058\n", + "[574.61445177 574.70334881]\n", + ".\\output\\sd_products_num0000000059\n", + ".\\output\\sd_attributes_num0000000059\n", + "[584.61445177 584.70334881]\n", + ".\\output\\sd_products_num0000000060\n", + ".\\output\\sd_attributes_num0000000060\n", + "[594.61445177 594.70334881]\n", + ".\\output\\sd_products_num0000000061\n", + ".\\output\\sd_attributes_num0000000061\n", + "[604.61445177 604.70334881]\n", + ".\\output\\sd_products_num0000000062\n", + ".\\output\\sd_attributes_num0000000062\n", + "[614.61445177 614.70334881]\n", + ".\\output\\sd_products_num0000000063\n", + ".\\output\\sd_attributes_num0000000063\n", + "[624.61445177 624.70334881]\n", + ".\\output\\sd_products_num0000000064\n", + ".\\output\\sd_attributes_num0000000064\n", + "[634.61445177 634.70334881]\n", + ".\\output\\sd_products_num0000000065\n", + ".\\output\\sd_attributes_num0000000065\n", + "[644.61445177 644.70334881]\n", + ".\\output\\sd_products_num0000000066\n", + ".\\output\\sd_attributes_num0000000066\n", + "[654.61445177 654.70334881]\n", + ".\\output\\sd_products_num0000000067\n", + ".\\output\\sd_attributes_num0000000067\n", + "[664.61445177 664.70334881]\n", + ".\\output\\sd_products_num0000000068\n", + ".\\output\\sd_attributes_num0000000068\n", + "[674.61445177 674.70334881]\n", + ".\\output\\sd_products_num0000000069\n", + ".\\output\\sd_attributes_num0000000069\n", + "[684.61445177 684.70334881]\n", + ".\\output\\sd_products_num0000000070\n", + ".\\output\\sd_attributes_num0000000070\n", + "[694.61445177 694.70334881]\n", + ".\\output\\sd_products_num0000000071\n", + ".\\output\\sd_attributes_num0000000071\n", + "[704.61445177 704.70334881]\n", + ".\\output\\sd_products_num0000000072\n", + ".\\output\\sd_attributes_num0000000072\n", + "[714.61445177 714.70334881]\n", + ".\\output\\sd_products_num0000000073\n", + ".\\output\\sd_attributes_num0000000073\n", + "[724.61445177 724.70334881]\n", + ".\\output\\sd_products_num0000000074\n", + ".\\output\\sd_attributes_num0000000074\n", + "[734.61445177 734.70334881]\n", + ".\\output\\sd_products_num0000000075\n", + ".\\output\\sd_attributes_num0000000075\n", + "[744.61445177 744.70334881]\n", + ".\\output\\sd_products_num0000000076\n", + ".\\output\\sd_attributes_num0000000076\n", + "[754.61445177 754.70334881]\n", + ".\\output\\sd_products_num0000000077\n", + ".\\output\\sd_attributes_num0000000077\n", + "[764.61445177 764.70334881]\n", + ".\\output\\sd_products_num0000000078\n", + ".\\output\\sd_attributes_num0000000078\n", + "[774.61445177 774.70334881]\n", + ".\\output\\sd_products_num0000000079\n", + ".\\output\\sd_attributes_num0000000079\n", + "[784.61445177 784.70334881]\n", + ".\\output\\sd_products_num0000000080\n", + ".\\output\\sd_attributes_num0000000080\n", + "[794.61445177 794.70334881]\n", + ".\\output\\sd_products_num0000000081\n", + ".\\output\\sd_attributes_num0000000081\n", + "[804.61445177 804.70334881]\n", + ".\\output\\sd_products_num0000000082\n", + ".\\output\\sd_attributes_num0000000082\n", + "[814.61445177 814.70334881]\n", + ".\\output\\sd_products_num0000000083\n", + ".\\output\\sd_attributes_num0000000083\n", + "[824.61445177 824.70334881]\n", + ".\\output\\sd_products_num0000000084\n", + ".\\output\\sd_attributes_num0000000084\n", + "[834.61445177 834.70334881]\n", + ".\\output\\sd_products_num0000000085\n", + ".\\output\\sd_attributes_num0000000085\n", + "[844.61445177 844.70334881]\n", + ".\\output\\sd_products_num0000000086\n", + ".\\output\\sd_attributes_num0000000086\n", + "[854.61445177 854.70334881]\n", + ".\\output\\sd_products_num0000000087\n", + ".\\output\\sd_attributes_num0000000087\n", + "[864.61445177 864.70334881]\n", + ".\\output\\sd_products_num0000000088\n", + ".\\output\\sd_attributes_num0000000088\n", + "[874.61445177 874.70334881]\n", + ".\\output\\sd_products_num0000000089\n", + ".\\output\\sd_attributes_num0000000089\n", + "[884.61445177 884.70334881]\n", + ".\\output\\sd_products_num0000000090\n", + ".\\output\\sd_attributes_num0000000090\n", + "[894.61445177 894.70334881]\n", + ".\\output\\sd_products_num0000000091\n", + ".\\output\\sd_attributes_num0000000091\n", + "[904.61445177 904.70334881]\n", + ".\\output\\sd_products_num0000000092\n", + ".\\output\\sd_attributes_num0000000092\n", + "[914.61445177 914.70334881]\n", + ".\\output\\sd_products_num0000000093\n", + ".\\output\\sd_attributes_num0000000093\n", + "[924.61445177 924.70334881]\n", + ".\\output\\sd_products_num0000000094\n", + ".\\output\\sd_attributes_num0000000094\n", + "[934.61445177 934.70334881]\n", + ".\\output\\sd_products_num0000000095\n", + ".\\output\\sd_attributes_num0000000095\n", + "[944.61445177 944.70334881]\n", + ".\\output\\sd_products_num0000000096\n", + ".\\output\\sd_attributes_num0000000096\n", + "[954.61445177 954.70334881]\n", + ".\\output\\sd_products_num0000000097\n", + ".\\output\\sd_attributes_num0000000097\n", + "[964.61445177 964.70334881]\n", + ".\\output\\sd_products_num0000000098\n", + ".\\output\\sd_attributes_num0000000098\n", + "[974.61445177 974.70334881]\n", + ".\\output\\sd_products_num0000000099\n", + ".\\output\\sd_attributes_num0000000099\n", + "[984.61445177 984.70334881]\n", + ".\\output\\sd_products_num0000000100\n", + ".\\output\\sd_attributes_num0000000100\n", + "[994.61445177 994.70334881]\n" + ] + } + ], + "source": [ + "e = VTKExporterParcel(n_sd=simulation.particulator.n_sd)\n", + "for step in settings.output_steps:\n", + " e.export_products(output, step)\n", + " e.export_attributes(output, step)\n", + "e.write_pvd()" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "id": "62bc5731", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Volume in drive C is OS\n", + " Volume Serial Number is 4AFE-B6B9\n", + "\n", + " Directory of c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\n", + "\n", + "11.08.2025 18:45 .\n", + "11.08.2025 17:25 ..\n", + "11.08.2025 18:45 9�510 sd_attributes.pvd\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000000.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000001.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000002.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000003.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000004.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000005.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000006.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000007.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000008.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000009.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000010.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000011.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000012.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000013.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000014.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000015.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000016.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000017.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000018.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000019.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000020.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000021.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000022.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000023.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000024.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000025.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000026.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000027.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000028.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000029.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000030.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000031.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000032.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000033.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000034.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000035.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000036.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000037.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000038.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000039.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000040.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000041.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000042.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000043.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000044.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000045.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000046.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000047.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000048.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000049.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000050.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000051.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000052.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000053.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000054.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000055.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000056.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000057.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000058.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000059.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000060.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000061.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000062.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000063.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000064.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000065.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000066.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000067.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000068.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000069.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000070.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000071.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000072.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000073.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000074.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000075.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000076.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000077.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000078.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000079.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000080.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000081.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000082.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000083.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000084.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000085.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000086.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000087.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000088.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000089.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000090.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000091.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000092.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000093.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000094.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000095.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000096.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000097.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000098.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000099.vtu\n", + "11.08.2025 18:45 11�368 sd_attributes_num0000000100.vtu\n", + "11.08.2025 18:45 9�308 sd_products.pvd\n", + "11.08.2025 18:45 15�943 sd_products_num0000000000.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000001.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000002.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000003.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000004.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000005.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000006.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000007.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000008.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000009.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000010.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000011.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000012.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000013.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000014.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000015.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000016.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000017.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000018.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000019.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000020.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000021.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000022.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000023.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000024.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000025.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000026.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000027.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000028.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000029.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000030.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000031.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000032.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000033.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000034.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000035.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000036.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000037.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000038.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000039.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000040.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000041.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000042.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000043.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000044.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000045.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000046.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000047.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000048.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000049.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000050.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000051.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000052.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000053.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000054.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000055.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000056.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000057.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000058.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000059.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000060.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000061.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000062.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000063.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000064.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000065.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000066.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000067.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000068.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000069.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000070.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000071.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000072.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000073.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000074.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000075.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000076.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000077.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000078.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000079.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000080.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000081.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000082.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000083.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000084.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000085.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000086.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000087.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000088.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000089.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000090.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000091.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000092.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000093.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000094.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000095.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000096.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000097.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000098.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000099.vtu\n", + "11.08.2025 18:45 15�943 sd_products_num0000000100.vtu\n", + " 204 File(s) 2�777�229 bytes\n", + " 2 Dir(s) 52�239�495�168 bytes free\n" + ] + } + ], + "source": [ + "!dir output" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a0a16bb", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51f96cac", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From b90172f9decbf5a63f388491834144d0175be01d Mon Sep 17 00:00:00 2001 From: olastrz Date: Mon, 1 Sep 2025 20:01:07 +0200 Subject: [PATCH 02/29] Seperate exporter from notebook --- PySDM/exporters/parcel_vtk_exporter.py | 121 +++ examples/PySDM_examples/Pyrcel/paraview.ipynb | 867 ++++-------------- 2 files changed, 281 insertions(+), 707 deletions(-) create mode 100644 PySDM/exporters/parcel_vtk_exporter.py diff --git a/PySDM/exporters/parcel_vtk_exporter.py b/PySDM/exporters/parcel_vtk_exporter.py new file mode 100644 index 000000000..48609af4b --- /dev/null +++ b/PySDM/exporters/parcel_vtk_exporter.py @@ -0,0 +1,121 @@ +""" +VTK Exporter for Pyrcel PySDM simulations. + +This module defines `VTKExporterPyrcel`, a subclass of `PySDM.exporters.VTKExporter`, +that writes simulation outputs to VTK format using `pyevtk`. It exports product +profiles (e.g., relative humidity) as unstructured grids and particle attributes +as point clouds, along with `.pvd` collection files for time-series visualization +in ParaView. +""" + +from pyevtk.hl import unstructuredGridToVTK, pointsToVTK +from pyevtk.vtk import VtkHexahedron, VtkGroup +import numpy as np + +from PySDM.exporters import VTKExporter + + +class VTKExporterPyrcel(VTKExporter): + """ + Custom VTK exporter for Pyrcel PySDM, exporting products as grids + and attributes as point clouds for ParaView visualization. + """ + + def __init__(self, n_sd): + super().__init__() + self.x = np.random.random(n_sd) # pylint: disable=invalid-name + self.y = np.random.random(n_sd) # pylint: disable=invalid-name + self.z = np.random.random(n_sd) # pylint: disable=invalid-name + + def write_pvd(self): + pvd_attributes = VtkGroup(self.attributes_file_path) + for key, value in self.exported_times["attributes"].items(): + pvd_attributes.addFile(key + ".vtu", sim_time=value) + pvd_attributes.save() + + pvd_products = VtkGroup(self.products_file_path) + for key, value in self.exported_times["products"].items(): + pvd_products.addFile(key + ".vtu", sim_time=value) + pvd_products.save() + + def export_products( + self, output, step, simulation + ): # pylint: disable=arguments-differ, too-many-locals + path = self.products_file_path + "_num" + self.add_leading_zeros(step) + + self.exported_times["products"][path] = step * simulation.particulator.dt + + n_levels = len(output["products"]["z"]) + n_vertices = 4 * n_levels + x = np.zeros(n_vertices) # pylint: disable=invalid-name + y = np.zeros(n_vertices) # pylint: disable=invalid-name + z = np.zeros(n_vertices) # pylint: disable=invalid-name + conn = [0, 1, 2, 3] + ctype = np.zeros(n_levels - 1) + ctype[:] = VtkHexahedron.tid + + _volume = ( + simulation.particulator.environment.mass_of_dry_air + / output["products"]["rhod"][0] + ) + _dz = output["products"]["z"][1] - output["products"]["z"][0] + for level in range(n_levels): + _z = output["products"]["z"][level] + if level > 0: + prev_to_curr_density_ratio = ( + output["products"]["rhod"][level - 1] + / output["products"]["rhod"][level] + ) + _volume *= prev_to_curr_density_ratio + _dz = ( + output["products"]["z"][level] - output["products"]["z"][level - 1] + ) + _area = _volume / _dz + _half_diagonal = (2 * _area) ** 0.5 + x[i := level * 4], y[i], z[i] = -_half_diagonal, -_half_diagonal, _z + x[i := i + 1], y[i], z[i] = -_half_diagonal, _half_diagonal, _z + x[i := i + 1], y[i], z[i] = _half_diagonal, _half_diagonal, _z + x[i := i + 1], y[i], z[i] = _half_diagonal, -_half_diagonal, _z + conn += [*range(4 * (level + 1), 4 * (level + 2))] * 2 + conn = np.asarray(conn[:-4]) + offset = np.asarray(range(8, 8 * n_levels, 8)) + + _ = {"test_pd": np.array([44] * n_vertices)} # pointData + + _RH = output["products"]["S_max_percent"] # pylint: disable=invalid-name + cell_data = {"RH": np.full(shape=(len(_RH) - 1,), fill_value=np.nan)} + cell_data["RH"][:step] = (np.array(_RH[:-1] + np.diff(_RH) / 2))[:step] + unstructuredGridToVTK( + path, + x, + y, + z, + connectivity=conn, + offsets=offset, + cell_types=ctype, + cellData=cell_data, + # pointData=point_data, + # fieldData=field_data, + ) + + def export_attributes( + self, output, step, simulation + ): # pylint: disable=arguments-differ + path = self.attributes_file_path + "_num" + self.add_leading_zeros(step) + self.exported_times["attributes"][path] = step * simulation.particulator.dt + + payload = {} + + for k in output["attributes"].keys(): + payload[k] = np.asarray(output["attributes"][k])[:, step].copy() + + if step != 0: + dz = ( + output["products"]["z"][step] - output["products"]["z"][step - 1] + ) # pylint: disable=invalid-name + if step == 1: + self.z *= dz + else: + self.z += dz + + print(pointsToVTK(path, self.x, self.y, self.z, data=payload)) diff --git a/examples/PySDM_examples/Pyrcel/paraview.ipynb b/examples/PySDM_examples/Pyrcel/paraview.ipynb index 81fcce9dc..d56ba6d0c 100644 --- a/examples/PySDM_examples/Pyrcel/paraview.ipynb +++ b/examples/PySDM_examples/Pyrcel/paraview.ipynb @@ -2,77 +2,90 @@ "cells": [ { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "6dcbcc6d", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\../../../PySDM/exporters/\n" + ] + } + ], "source": [ "import numpy as np\n", "from PySDM import Formulae\n", "from PySDM.physics import si\n", "from PySDM.initialisation.spectra import Lognormal\n", "from PySDM.products import (\n", - " ParcelDisplacement, AmbientTemperature, AmbientDryAirDensity, AmbientRelativeHumidity,\n", - " ParticleSizeSpectrumPerVolume, ParticleVolumeVersusRadiusLogarithmSpectrum\n", + " ParcelDisplacement,\n", + " AmbientTemperature,\n", + " AmbientDryAirDensity,\n", + " AmbientRelativeHumidity,\n", + " ParticleSizeSpectrumPerVolume,\n", + " ParticleVolumeVersusRadiusLogarithmSpectrum,\n", ")\n", "\n", - "from PySDM_examples.Pyrcel import Settings, Simulation" + "from PySDM_examples.Pyrcel import Settings, Simulation\n", + "import sys\n", + "import os\n", + "\n", + "notebook_dir = os.path.dirname(os.path.abspath(\"__file__\"))\n", + "exporters_path = os.path.join(notebook_dir, \"../../../PySDM/exporters/\")\n", + "print(exporters_path)\n", + "sys.path.append(exporters_path)\n", + "\n", + "from parcel_vtk_exporter import VTKExporterPyrcel" ] }, { "cell_type": "code", - "execution_count": 106, + "execution_count": 8, "id": "cd6288b5", "metadata": {}, "outputs": [], "source": [ "settings = Settings(\n", - " dz = 10 * si.m,\n", - " n_sd_per_mode = (1, 1),\n", - " aerosol_modes_by_kappa = {\n", - " .54: Lognormal(\n", - " norm_factor=850 / si.cm ** 3,\n", - " m_mode=15 * si.nm,\n", - " s_geom=1.6\n", - " ),\n", - " 1.2: Lognormal(\n", - " norm_factor=10 / si.cm ** 3,\n", - " m_mode=850 * si.nm,\n", - " s_geom=1.2\n", - " )\n", + " dz=10 * si.m,\n", + " n_sd_per_mode=(1, 1),\n", + " aerosol_modes_by_kappa={\n", + " 0.54: Lognormal(norm_factor=850 / si.cm**3, m_mode=15 * si.nm, s_geom=1.6),\n", + " 1.2: Lognormal(norm_factor=10 / si.cm**3, m_mode=850 * si.nm, s_geom=1.2),\n", " },\n", - " vertical_velocity = 1.0 * si.m / si.s,\n", - " initial_pressure = 775 * si.mbar,\n", - " initial_temperature = 274 * si.K,\n", - " initial_relative_humidity = .98,\n", - " displacement = 1000 * si.m,\n", - " formulae = Formulae(constants={'MAC': .3})\n", + " vertical_velocity=1.0 * si.m / si.s,\n", + " initial_pressure=775 * si.mbar,\n", + " initial_temperature=274 * si.K,\n", + " initial_relative_humidity=0.98,\n", + " displacement=1000 * si.m,\n", + " formulae=Formulae(constants={\"MAC\": 0.3}),\n", ")\n", "\n", "dry_radius_bin_edges = np.logspace(\n", - " np.log10(1e-3 * si.um),\n", - " np.log10(5e0 * si.um),\n", - " 33, endpoint=False\n", + " np.log10(1e-3 * si.um), np.log10(5e0 * si.um), 33, endpoint=False\n", ")\n", "\n", - "simulation = Simulation(settings, products=(\n", - " ParcelDisplacement(\n", - " name='z'),\n", - " AmbientRelativeHumidity(\n", - " name='S_max_percent', unit='%', var='RH'),\n", - " AmbientTemperature(\n", - " name='T'),\n", - " ParticleSizeSpectrumPerVolume(\n", - " name='dry:dN/dR', radius_bins_edges=dry_radius_bin_edges, dry=True),\n", - " ParticleVolumeVersusRadiusLogarithmSpectrum(\n", - " name='dry:dV/dlnR', radius_bins_edges=dry_radius_bin_edges, dry=True),\n", - " AmbientDryAirDensity(),\n", - "))" + "simulation = Simulation(\n", + " settings,\n", + " products=(\n", + " ParcelDisplacement(name=\"z\"),\n", + " AmbientRelativeHumidity(name=\"S_max_percent\", unit=\"%\", var=\"RH\"),\n", + " AmbientTemperature(name=\"T\"),\n", + " ParticleSizeSpectrumPerVolume(\n", + " name=\"dry:dN/dR\", radius_bins_edges=dry_radius_bin_edges, dry=True\n", + " ),\n", + " ParticleVolumeVersusRadiusLogarithmSpectrum(\n", + " name=\"dry:dV/dlnR\", radius_bins_edges=dry_radius_bin_edges, dry=True\n", + " ),\n", + " AmbientDryAirDensity(),\n", + " ),\n", + ")" ] }, { "cell_type": "code", - "execution_count": 107, + "execution_count": 9, "id": "3ff50a25", "metadata": {}, "outputs": [], @@ -82,119 +95,7 @@ }, { "cell_type": "code", - "execution_count": 108, - "id": "d645954c", - "metadata": {}, - "outputs": [], - "source": [ - "from pyevtk.hl import unstructuredGridToVTK, pointsToVTK\n", - "from pyevtk.vtk import VtkHexahedron, VtkGroup\n", - "import numpy as np\n", - "\n", - "from PySDM.exporters import VTKExporter\n", - "\n", - "\n", - "class VTKExporterParcel(VTKExporter):\n", - " def __init__(self, n_sd):\n", - " super().__init__()\n", - " self.x = np.random.random(n_sd)\n", - " self.y = np.random.random(n_sd)\n", - " self.z = np.random.random(n_sd)\n", - "\n", - " def write_pvd(self):\n", - " pvd_attributes = VtkGroup(self.attributes_file_path)\n", - " for k, v in self.exported_times[\"attributes\"].items():\n", - " pvd_attributes.addFile(k + \".vtu\", sim_time=v)\n", - " pvd_attributes.save()\n", - "\n", - " pvd_products = VtkGroup(self.products_file_path)\n", - " for k, v in self.exported_times[\"products\"].items():\n", - " pvd_products.addFile(k + \".vtu\", sim_time=v)\n", - " pvd_products.save()\n", - "\n", - " def export_products(self, output, step):\n", - " path = (\n", - " self.products_file_path\n", - " + \"_num\"\n", - " + self.add_leading_zeros(step)\n", - " )\n", - " print(path)\n", - " self.exported_times[\"products\"][path] = (\n", - " step * simulation.particulator.dt\n", - " )\n", - "\n", - " n_levels = len(output['products']['z'])\n", - " n_vertices = 4 * n_levels\n", - " x = np.zeros(n_vertices)\n", - " y = np.zeros(n_vertices)\n", - " z = np.zeros(n_vertices)\n", - " conn = [0, 1, 2, 3]\n", - " ctype = np.zeros(n_levels - 1)\n", - " ctype[:] = VtkHexahedron.tid\n", - "\n", - " _volume = simulation.particulator.environment.mass_of_dry_air / output['products']['rhod'][0]\n", - " _dz = output['products']['z'][1] - output['products']['z'][0]\n", - " for level in range(n_levels): \n", - " _z = output['products']['z'][level] \n", - " if level > 0:\n", - " prev_to_curr_density_ratio = output['products']['rhod'][level-1] / output['products']['rhod'][level]\n", - " _volume *= prev_to_curr_density_ratio\n", - " _dz = output['products']['z'][level] - output['products']['z'][level-1]\n", - " _area = _volume / _dz\n", - " _half_diagonal = (2 * _area) ** .5\n", - " x[i := level * 4], y[i], z[i] = -_half_diagonal, -_half_diagonal, _z \n", - " x[i := i + 1], y[i], z[i] = -_half_diagonal, _half_diagonal, _z\n", - " x[i := i + 1], y[i], z[i] = _half_diagonal, _half_diagonal, _z\n", - " x[i := i + 1], y[i], z[i] = _half_diagonal, -_half_diagonal, _z\n", - " conn += [*range(4 * (level + 1), 4 * (level + 2))] * 2\n", - " conn = np.asarray(conn[:-4])\n", - " offset = np.asarray(range(8, 8 * n_levels, 8))\n", - "\n", - " point_data = {\"test_pd\": np.array([44] * n_vertices)}\n", - "\n", - " _RH = output['products']['S_max_percent']\n", - " cell_data = {\"RH\": np.full(shape=(len(_RH)-1,), fill_value=np.nan)}\n", - " cell_data[\"RH\"][:step] = (np.array(_RH[:-1] + np.diff(_RH)/2))[:step]\n", - " unstructuredGridToVTK(\n", - " path,\n", - " x,\n", - " y,\n", - " z,\n", - " connectivity=conn,\n", - " offsets=offset,\n", - " cell_types=ctype,\n", - " cellData=cell_data,\n", - " #pointData=point_data,\n", - " #fieldData=field_data,\n", - " )\n", - "\n", - " def export_attributes(self, output, step):\n", - " path = (\n", - " self.attributes_file_path\n", - " + \"_num\"\n", - " + self.add_leading_zeros(step)\n", - " )\n", - " self.exported_times[\"attributes\"][path] = step * simulation.particulator.dt\n", - " print(path)\n", - " payload = {}\n", - "\n", - " for k in output[\"attributes\"].keys():\n", - " payload[k] = np.asarray(output[\"attributes\"][k])[:,step].copy()\n", - "\n", - " if step != 0:\n", - " dz = output['products']['z'][step] - output['products']['z'][step - 1] \n", - " if step == 1:\n", - " self.z *= dz\n", - " else:\n", - " self.z += dz\n", - " print(self.z)\n", - "\n", - " pointsToVTK(path, self.x, self.y, self.z, data=payload)" - ] - }, - { - "cell_type": "code", - "execution_count": 109, + "execution_count": 10, "id": "15d59657", "metadata": {}, "outputs": [ @@ -202,565 +103,117 @@ "name": "stdout", "output_type": "stream", "text": [ - ".\\output\\sd_products_num0000000000\n", - ".\\output\\sd_attributes_num0000000000\n", - "[0.46144518 0.47033488]\n", - ".\\output\\sd_products_num0000000001\n", - ".\\output\\sd_attributes_num0000000001\n", - "[4.61445177 4.70334881]\n", - ".\\output\\sd_products_num0000000002\n", - ".\\output\\sd_attributes_num0000000002\n", - "[14.61445177 14.70334881]\n", - ".\\output\\sd_products_num0000000003\n", - ".\\output\\sd_attributes_num0000000003\n", - "[24.61445177 24.70334881]\n", - ".\\output\\sd_products_num0000000004\n", - ".\\output\\sd_attributes_num0000000004\n", - "[34.61445177 34.70334881]\n", - ".\\output\\sd_products_num0000000005\n", - ".\\output\\sd_attributes_num0000000005\n", - "[44.61445177 44.70334881]\n", - ".\\output\\sd_products_num0000000006\n", - ".\\output\\sd_attributes_num0000000006\n", - "[54.61445177 54.70334881]\n", - ".\\output\\sd_products_num0000000007\n", - ".\\output\\sd_attributes_num0000000007\n", - "[64.61445177 64.70334881]\n", - ".\\output\\sd_products_num0000000008\n", - ".\\output\\sd_attributes_num0000000008\n", - "[74.61445177 74.70334881]\n", - ".\\output\\sd_products_num0000000009\n", - ".\\output\\sd_attributes_num0000000009\n", - "[84.61445177 84.70334881]\n", - ".\\output\\sd_products_num0000000010\n", - ".\\output\\sd_attributes_num0000000010\n", - "[94.61445177 94.70334881]\n", - ".\\output\\sd_products_num0000000011\n", - ".\\output\\sd_attributes_num0000000011\n", - "[104.61445177 104.70334881]\n", - ".\\output\\sd_products_num0000000012\n", - ".\\output\\sd_attributes_num0000000012\n", - "[114.61445177 114.70334881]\n", - ".\\output\\sd_products_num0000000013\n", - ".\\output\\sd_attributes_num0000000013\n", - "[124.61445177 124.70334881]\n", - ".\\output\\sd_products_num0000000014\n", - ".\\output\\sd_attributes_num0000000014\n", - "[134.61445177 134.70334881]\n", - ".\\output\\sd_products_num0000000015\n", - ".\\output\\sd_attributes_num0000000015\n", - "[144.61445177 144.70334881]\n", - ".\\output\\sd_products_num0000000016\n", - ".\\output\\sd_attributes_num0000000016\n", - "[154.61445177 154.70334881]\n", - ".\\output\\sd_products_num0000000017\n", - ".\\output\\sd_attributes_num0000000017\n", - "[164.61445177 164.70334881]\n", - ".\\output\\sd_products_num0000000018\n", - ".\\output\\sd_attributes_num0000000018\n", - "[174.61445177 174.70334881]\n", - ".\\output\\sd_products_num0000000019\n", - ".\\output\\sd_attributes_num0000000019\n", - "[184.61445177 184.70334881]\n", - ".\\output\\sd_products_num0000000020\n", - ".\\output\\sd_attributes_num0000000020\n", - "[194.61445177 194.70334881]\n", - ".\\output\\sd_products_num0000000021\n", - ".\\output\\sd_attributes_num0000000021\n", - "[204.61445177 204.70334881]\n", - ".\\output\\sd_products_num0000000022\n", - ".\\output\\sd_attributes_num0000000022\n", - "[214.61445177 214.70334881]\n", - ".\\output\\sd_products_num0000000023\n", - ".\\output\\sd_attributes_num0000000023\n", - "[224.61445177 224.70334881]\n", - ".\\output\\sd_products_num0000000024\n", - ".\\output\\sd_attributes_num0000000024\n", - "[234.61445177 234.70334881]\n", - ".\\output\\sd_products_num0000000025\n", - ".\\output\\sd_attributes_num0000000025\n", - "[244.61445177 244.70334881]\n", - ".\\output\\sd_products_num0000000026\n", - ".\\output\\sd_attributes_num0000000026\n", - "[254.61445177 254.70334881]\n", - ".\\output\\sd_products_num0000000027\n", - ".\\output\\sd_attributes_num0000000027\n", - "[264.61445177 264.70334881]\n", - ".\\output\\sd_products_num0000000028\n", - ".\\output\\sd_attributes_num0000000028\n", - "[274.61445177 274.70334881]\n", - ".\\output\\sd_products_num0000000029\n", - ".\\output\\sd_attributes_num0000000029\n", - "[284.61445177 284.70334881]\n", - ".\\output\\sd_products_num0000000030\n", - ".\\output\\sd_attributes_num0000000030\n", - "[294.61445177 294.70334881]\n", - ".\\output\\sd_products_num0000000031\n", - ".\\output\\sd_attributes_num0000000031\n", - "[304.61445177 304.70334881]\n", - ".\\output\\sd_products_num0000000032\n", - ".\\output\\sd_attributes_num0000000032\n", - "[314.61445177 314.70334881]\n", - ".\\output\\sd_products_num0000000033\n", - ".\\output\\sd_attributes_num0000000033\n", - "[324.61445177 324.70334881]\n", - ".\\output\\sd_products_num0000000034\n", - ".\\output\\sd_attributes_num0000000034\n", - "[334.61445177 334.70334881]\n", - ".\\output\\sd_products_num0000000035\n", - ".\\output\\sd_attributes_num0000000035\n", - "[344.61445177 344.70334881]\n", - ".\\output\\sd_products_num0000000036\n", - ".\\output\\sd_attributes_num0000000036\n", - "[354.61445177 354.70334881]\n", - ".\\output\\sd_products_num0000000037\n", - ".\\output\\sd_attributes_num0000000037\n", - "[364.61445177 364.70334881]\n", - ".\\output\\sd_products_num0000000038\n", - ".\\output\\sd_attributes_num0000000038\n", - "[374.61445177 374.70334881]\n", - ".\\output\\sd_products_num0000000039\n", - ".\\output\\sd_attributes_num0000000039\n", - "[384.61445177 384.70334881]\n", - ".\\output\\sd_products_num0000000040\n", - ".\\output\\sd_attributes_num0000000040\n", - "[394.61445177 394.70334881]\n", - ".\\output\\sd_products_num0000000041\n", - ".\\output\\sd_attributes_num0000000041\n", - "[404.61445177 404.70334881]\n", - ".\\output\\sd_products_num0000000042\n", - ".\\output\\sd_attributes_num0000000042\n", - "[414.61445177 414.70334881]\n", - ".\\output\\sd_products_num0000000043\n", - ".\\output\\sd_attributes_num0000000043\n", - "[424.61445177 424.70334881]\n", - ".\\output\\sd_products_num0000000044\n", - ".\\output\\sd_attributes_num0000000044\n", - "[434.61445177 434.70334881]\n", - ".\\output\\sd_products_num0000000045\n", - ".\\output\\sd_attributes_num0000000045\n", - "[444.61445177 444.70334881]\n", - ".\\output\\sd_products_num0000000046\n", - ".\\output\\sd_attributes_num0000000046\n", - "[454.61445177 454.70334881]\n", - ".\\output\\sd_products_num0000000047\n", - ".\\output\\sd_attributes_num0000000047\n", - "[464.61445177 464.70334881]\n", - ".\\output\\sd_products_num0000000048\n", - ".\\output\\sd_attributes_num0000000048\n", - "[474.61445177 474.70334881]\n", - ".\\output\\sd_products_num0000000049\n", - ".\\output\\sd_attributes_num0000000049\n", - "[484.61445177 484.70334881]\n", - ".\\output\\sd_products_num0000000050\n", - ".\\output\\sd_attributes_num0000000050\n", - "[494.61445177 494.70334881]\n", - ".\\output\\sd_products_num0000000051\n", - ".\\output\\sd_attributes_num0000000051\n", - "[504.61445177 504.70334881]\n", - ".\\output\\sd_products_num0000000052\n", - ".\\output\\sd_attributes_num0000000052\n", - "[514.61445177 514.70334881]\n", - ".\\output\\sd_products_num0000000053\n", - ".\\output\\sd_attributes_num0000000053\n", - "[524.61445177 524.70334881]\n", - ".\\output\\sd_products_num0000000054\n", - ".\\output\\sd_attributes_num0000000054\n", - "[534.61445177 534.70334881]\n", - ".\\output\\sd_products_num0000000055\n", - ".\\output\\sd_attributes_num0000000055\n", - "[544.61445177 544.70334881]\n", - ".\\output\\sd_products_num0000000056\n", - ".\\output\\sd_attributes_num0000000056\n", - "[554.61445177 554.70334881]\n", - ".\\output\\sd_products_num0000000057\n", - ".\\output\\sd_attributes_num0000000057\n", - "[564.61445177 564.70334881]\n", - ".\\output\\sd_products_num0000000058\n", - ".\\output\\sd_attributes_num0000000058\n", - "[574.61445177 574.70334881]\n", - ".\\output\\sd_products_num0000000059\n", - ".\\output\\sd_attributes_num0000000059\n", - "[584.61445177 584.70334881]\n", - ".\\output\\sd_products_num0000000060\n", - ".\\output\\sd_attributes_num0000000060\n", - "[594.61445177 594.70334881]\n", - ".\\output\\sd_products_num0000000061\n", - ".\\output\\sd_attributes_num0000000061\n", - "[604.61445177 604.70334881]\n", - ".\\output\\sd_products_num0000000062\n", - ".\\output\\sd_attributes_num0000000062\n", - "[614.61445177 614.70334881]\n", - ".\\output\\sd_products_num0000000063\n", - ".\\output\\sd_attributes_num0000000063\n", - "[624.61445177 624.70334881]\n", - ".\\output\\sd_products_num0000000064\n", - ".\\output\\sd_attributes_num0000000064\n", - "[634.61445177 634.70334881]\n", - ".\\output\\sd_products_num0000000065\n", - ".\\output\\sd_attributes_num0000000065\n", - "[644.61445177 644.70334881]\n", - ".\\output\\sd_products_num0000000066\n", - ".\\output\\sd_attributes_num0000000066\n", - "[654.61445177 654.70334881]\n", - ".\\output\\sd_products_num0000000067\n", - ".\\output\\sd_attributes_num0000000067\n", - "[664.61445177 664.70334881]\n", - ".\\output\\sd_products_num0000000068\n", - ".\\output\\sd_attributes_num0000000068\n", - "[674.61445177 674.70334881]\n", - ".\\output\\sd_products_num0000000069\n", - ".\\output\\sd_attributes_num0000000069\n", - "[684.61445177 684.70334881]\n", - ".\\output\\sd_products_num0000000070\n", - ".\\output\\sd_attributes_num0000000070\n", - "[694.61445177 694.70334881]\n", - ".\\output\\sd_products_num0000000071\n", - ".\\output\\sd_attributes_num0000000071\n", - "[704.61445177 704.70334881]\n", - ".\\output\\sd_products_num0000000072\n", - ".\\output\\sd_attributes_num0000000072\n", - "[714.61445177 714.70334881]\n", - ".\\output\\sd_products_num0000000073\n", - ".\\output\\sd_attributes_num0000000073\n", - "[724.61445177 724.70334881]\n", - ".\\output\\sd_products_num0000000074\n", - ".\\output\\sd_attributes_num0000000074\n", - "[734.61445177 734.70334881]\n", - ".\\output\\sd_products_num0000000075\n", - ".\\output\\sd_attributes_num0000000075\n", - "[744.61445177 744.70334881]\n", - ".\\output\\sd_products_num0000000076\n", - ".\\output\\sd_attributes_num0000000076\n", - "[754.61445177 754.70334881]\n", - ".\\output\\sd_products_num0000000077\n", - ".\\output\\sd_attributes_num0000000077\n", - "[764.61445177 764.70334881]\n", - ".\\output\\sd_products_num0000000078\n", - ".\\output\\sd_attributes_num0000000078\n", - "[774.61445177 774.70334881]\n", - ".\\output\\sd_products_num0000000079\n", - ".\\output\\sd_attributes_num0000000079\n", - "[784.61445177 784.70334881]\n", - ".\\output\\sd_products_num0000000080\n", - ".\\output\\sd_attributes_num0000000080\n", - "[794.61445177 794.70334881]\n", - ".\\output\\sd_products_num0000000081\n", - ".\\output\\sd_attributes_num0000000081\n", - "[804.61445177 804.70334881]\n", - ".\\output\\sd_products_num0000000082\n", - ".\\output\\sd_attributes_num0000000082\n", - "[814.61445177 814.70334881]\n", - ".\\output\\sd_products_num0000000083\n", - ".\\output\\sd_attributes_num0000000083\n", - "[824.61445177 824.70334881]\n", - ".\\output\\sd_products_num0000000084\n", - ".\\output\\sd_attributes_num0000000084\n", - "[834.61445177 834.70334881]\n", - ".\\output\\sd_products_num0000000085\n", - ".\\output\\sd_attributes_num0000000085\n", - "[844.61445177 844.70334881]\n", - ".\\output\\sd_products_num0000000086\n", - ".\\output\\sd_attributes_num0000000086\n", - "[854.61445177 854.70334881]\n", - ".\\output\\sd_products_num0000000087\n", - ".\\output\\sd_attributes_num0000000087\n", - "[864.61445177 864.70334881]\n", - ".\\output\\sd_products_num0000000088\n", - ".\\output\\sd_attributes_num0000000088\n", - "[874.61445177 874.70334881]\n", - ".\\output\\sd_products_num0000000089\n", - ".\\output\\sd_attributes_num0000000089\n", - "[884.61445177 884.70334881]\n", - ".\\output\\sd_products_num0000000090\n", - ".\\output\\sd_attributes_num0000000090\n", - "[894.61445177 894.70334881]\n", - ".\\output\\sd_products_num0000000091\n", - ".\\output\\sd_attributes_num0000000091\n", - "[904.61445177 904.70334881]\n", - ".\\output\\sd_products_num0000000092\n", - ".\\output\\sd_attributes_num0000000092\n", - "[914.61445177 914.70334881]\n", - ".\\output\\sd_products_num0000000093\n", - ".\\output\\sd_attributes_num0000000093\n", - "[924.61445177 924.70334881]\n", - ".\\output\\sd_products_num0000000094\n", - ".\\output\\sd_attributes_num0000000094\n", - "[934.61445177 934.70334881]\n", - ".\\output\\sd_products_num0000000095\n", - ".\\output\\sd_attributes_num0000000095\n", - "[944.61445177 944.70334881]\n", - ".\\output\\sd_products_num0000000096\n", - ".\\output\\sd_attributes_num0000000096\n", - "[954.61445177 954.70334881]\n", - ".\\output\\sd_products_num0000000097\n", - ".\\output\\sd_attributes_num0000000097\n", - "[964.61445177 964.70334881]\n", - ".\\output\\sd_products_num0000000098\n", - ".\\output\\sd_attributes_num0000000098\n", - "[974.61445177 974.70334881]\n", - ".\\output\\sd_products_num0000000099\n", - ".\\output\\sd_attributes_num0000000099\n", - "[984.61445177 984.70334881]\n", - ".\\output\\sd_products_num0000000100\n", - ".\\output\\sd_attributes_num0000000100\n", - "[994.61445177 994.70334881]\n" + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000000.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000001.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000002.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000003.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000004.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000005.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000006.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000007.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000008.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000009.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000010.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000011.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000012.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000013.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000014.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000015.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000016.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000017.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000018.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000019.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000020.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000021.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000022.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000023.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000024.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000025.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000026.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000027.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000028.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000029.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000030.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000031.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000032.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000033.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000034.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000035.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000036.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000037.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000038.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000039.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000040.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000041.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000042.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000043.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000044.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000045.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000046.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000047.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000048.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000049.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000050.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000051.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000052.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000053.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000054.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000055.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000056.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000057.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000058.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000059.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000060.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000061.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000062.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000063.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000064.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000065.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000066.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000067.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000068.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000069.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000070.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000071.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000072.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000073.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000074.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000075.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000076.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000077.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000078.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000079.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000080.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000081.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000082.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000083.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000084.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000085.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000086.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000087.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000088.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000089.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000090.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000091.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000092.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000093.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000094.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000095.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000096.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000097.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000098.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000099.vtu\n", + "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000100.vtu\n" ] } ], "source": [ - "e = VTKExporterParcel(n_sd=simulation.particulator.n_sd)\n", + "e = VTKExporterPyrcel(n_sd=simulation.particulator.n_sd)\n", "for step in settings.output_steps:\n", - " e.export_products(output, step)\n", - " e.export_attributes(output, step)\n", + " e.export_products(output, step, simulation)\n", + " e.export_attributes(output, step, simulation)\n", "e.write_pvd()" ] - }, - { - "cell_type": "code", - "execution_count": 96, - "id": "62bc5731", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Volume in drive C is OS\n", - " Volume Serial Number is 4AFE-B6B9\n", - "\n", - " Directory of c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\n", - "\n", - "11.08.2025 18:45 .\n", - "11.08.2025 17:25 ..\n", - "11.08.2025 18:45 9�510 sd_attributes.pvd\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000000.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000001.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000002.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000003.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000004.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000005.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000006.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000007.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000008.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000009.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000010.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000011.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000012.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000013.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000014.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000015.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000016.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000017.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000018.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000019.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000020.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000021.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000022.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000023.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000024.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000025.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000026.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000027.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000028.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000029.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000030.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000031.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000032.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000033.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000034.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000035.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000036.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000037.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000038.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000039.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000040.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000041.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000042.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000043.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000044.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000045.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000046.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000047.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000048.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000049.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000050.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000051.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000052.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000053.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000054.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000055.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000056.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000057.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000058.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000059.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000060.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000061.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000062.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000063.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000064.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000065.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000066.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000067.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000068.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000069.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000070.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000071.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000072.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000073.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000074.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000075.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000076.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000077.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000078.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000079.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000080.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000081.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000082.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000083.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000084.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000085.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000086.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000087.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000088.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000089.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000090.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000091.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000092.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000093.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000094.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000095.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000096.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000097.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000098.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000099.vtu\n", - "11.08.2025 18:45 11�368 sd_attributes_num0000000100.vtu\n", - "11.08.2025 18:45 9�308 sd_products.pvd\n", - "11.08.2025 18:45 15�943 sd_products_num0000000000.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000001.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000002.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000003.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000004.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000005.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000006.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000007.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000008.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000009.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000010.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000011.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000012.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000013.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000014.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000015.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000016.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000017.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000018.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000019.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000020.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000021.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000022.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000023.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000024.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000025.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000026.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000027.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000028.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000029.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000030.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000031.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000032.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000033.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000034.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000035.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000036.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000037.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000038.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000039.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000040.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000041.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000042.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000043.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000044.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000045.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000046.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000047.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000048.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000049.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000050.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000051.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000052.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000053.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000054.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000055.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000056.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000057.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000058.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000059.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000060.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000061.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000062.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000063.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000064.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000065.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000066.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000067.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000068.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000069.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000070.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000071.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000072.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000073.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000074.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000075.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000076.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000077.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000078.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000079.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000080.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000081.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000082.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000083.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000084.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000085.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000086.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000087.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000088.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000089.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000090.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000091.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000092.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000093.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000094.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000095.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000096.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000097.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000098.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000099.vtu\n", - "11.08.2025 18:45 15�943 sd_products_num0000000100.vtu\n", - " 204 File(s) 2�777�229 bytes\n", - " 2 Dir(s) 52�239�495�168 bytes free\n" - ] - } - ], - "source": [ - "!dir output" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7a0a16bb", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "51f96cac", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { From 282f098544659a6b8891019e28dc632ed4331d54 Mon Sep 17 00:00:00 2001 From: olastrz Date: Sun, 5 Oct 2025 13:17:15 +0200 Subject: [PATCH 03/29] first version of paraview script --- PySDM/exporters/parcel_vtk_exporter.py | 82 +++-- examples/PySDM_examples/Pyrcel/paraview.ipynb | 136 +------ .../Pyrcel/paraview_simulation.py | 221 +++++++++++ examples/PySDM_examples/Pyrcel/simulation.py | 2 +- .../calc2.py | 343 ++++++++++++++++++ .../no_glyphs.py | 341 +++++++++++++++++ 6 files changed, 968 insertions(+), 157 deletions(-) create mode 100644 examples/PySDM_examples/Pyrcel/paraview_simulation.py create mode 100644 examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py create mode 100644 examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py diff --git a/PySDM/exporters/parcel_vtk_exporter.py b/PySDM/exporters/parcel_vtk_exporter.py index 48609af4b..1b58732da 100644 --- a/PySDM/exporters/parcel_vtk_exporter.py +++ b/PySDM/exporters/parcel_vtk_exporter.py @@ -21,11 +21,29 @@ class VTKExporterPyrcel(VTKExporter): and attributes as point clouds for ParaView visualization. """ - def __init__(self, n_sd): + def __init__(self, n_sd, output, mass_of_dry_air): super().__init__() + self.output = output self.x = np.random.random(n_sd) # pylint: disable=invalid-name self.y = np.random.random(n_sd) # pylint: disable=invalid-name self.z = np.random.random(n_sd) # pylint: disable=invalid-name + self.half_diagonal = [] + self.n_levels = len(self.output["products"]["z"]) + + _volume = mass_of_dry_air / output["products"]["rhod"][0] + _dz = output["products"]["z"][1] - output["products"]["z"][0] + for level in range(self.n_levels): + if level > 0: + prev_to_curr_density_ratio = ( + output["products"]["rhod"][level - 1] + / output["products"]["rhod"][level] + ) + _volume *= prev_to_curr_density_ratio + _dz = ( + output["products"]["z"][level] - output["products"]["z"][level - 1] + ) + _area = _volume / _dz + self.half_diagonal.append((2 * _area) ** 0.5) def write_pvd(self): pvd_attributes = VtkGroup(self.attributes_file_path) @@ -39,50 +57,33 @@ def write_pvd(self): pvd_products.save() def export_products( - self, output, step, simulation + self, step, simulation ): # pylint: disable=arguments-differ, too-many-locals path = self.products_file_path + "_num" + self.add_leading_zeros(step) - self.exported_times["products"][path] = step * simulation.particulator.dt - n_levels = len(output["products"]["z"]) - n_vertices = 4 * n_levels + n_vertices = 4 * self.n_levels x = np.zeros(n_vertices) # pylint: disable=invalid-name y = np.zeros(n_vertices) # pylint: disable=invalid-name z = np.zeros(n_vertices) # pylint: disable=invalid-name conn = [0, 1, 2, 3] - ctype = np.zeros(n_levels - 1) + ctype = np.zeros(self.n_levels - 1) ctype[:] = VtkHexahedron.tid - _volume = ( - simulation.particulator.environment.mass_of_dry_air - / output["products"]["rhod"][0] - ) - _dz = output["products"]["z"][1] - output["products"]["z"][0] - for level in range(n_levels): - _z = output["products"]["z"][level] - if level > 0: - prev_to_curr_density_ratio = ( - output["products"]["rhod"][level - 1] - / output["products"]["rhod"][level] - ) - _volume *= prev_to_curr_density_ratio - _dz = ( - output["products"]["z"][level] - output["products"]["z"][level - 1] - ) - _area = _volume / _dz - _half_diagonal = (2 * _area) ** 0.5 - x[i := level * 4], y[i], z[i] = -_half_diagonal, -_half_diagonal, _z - x[i := i + 1], y[i], z[i] = -_half_diagonal, _half_diagonal, _z - x[i := i + 1], y[i], z[i] = _half_diagonal, _half_diagonal, _z - x[i := i + 1], y[i], z[i] = _half_diagonal, -_half_diagonal, _z + for level in range(self.n_levels): + hd = self.half_diagonal[level] + _z = self.output["products"]["z"][level] + x[i := level * 4], y[i], z[i] = -hd, -hd, _z + x[i := i + 1], y[i], z[i] = -hd, hd, _z + x[i := i + 1], y[i], z[i] = hd, hd, _z + x[i := i + 1], y[i], z[i] = hd, -hd, _z conn += [*range(4 * (level + 1), 4 * (level + 2))] * 2 conn = np.asarray(conn[:-4]) - offset = np.asarray(range(8, 8 * n_levels, 8)) + offset = np.asarray(range(8, 8 * self.n_levels, 8)) _ = {"test_pd": np.array([44] * n_vertices)} # pointData - _RH = output["products"]["S_max_percent"] # pylint: disable=invalid-name + _RH = self.output["products"]["S_max_percent"] # pylint: disable=invalid-name cell_data = {"RH": np.full(shape=(len(_RH) - 1,), fill_value=np.nan)} cell_data["RH"][:step] = (np.array(_RH[:-1] + np.diff(_RH) / 2))[:step] unstructuredGridToVTK( @@ -98,24 +99,29 @@ def export_products( # fieldData=field_data, ) - def export_attributes( - self, output, step, simulation - ): # pylint: disable=arguments-differ + def export_attributes(self, step, simulation): # pylint: disable=arguments-differ path = self.attributes_file_path + "_num" + self.add_leading_zeros(step) self.exported_times["attributes"][path] = step * simulation.particulator.dt payload = {} - for k in output["attributes"].keys(): - payload[k] = np.asarray(output["attributes"][k])[:, step].copy() - + for k in self.output["attributes"].keys(): + payload[k] = np.asarray(self.output["attributes"][k])[:, step].copy() + # payload["size"] = np.full(simulation.particulator.n_sd, 100.0) if step != 0: dz = ( - output["products"]["z"][step] - output["products"]["z"][step - 1] + self.output["products"]["z"][step] + - self.output["products"]["z"][step - 1] ) # pylint: disable=invalid-name if step == 1: self.z *= dz else: self.z += dz - print(pointsToVTK(path, self.x, self.y, self.z, data=payload)) + pointsToVTK( + path, + 2 * (self.x - 0.5) * self.half_diagonal[step], + 2 * (self.y - 0.5) * self.half_diagonal[step], + self.z, + data=payload, + ) diff --git a/examples/PySDM_examples/Pyrcel/paraview.ipynb b/examples/PySDM_examples/Pyrcel/paraview.ipynb index d56ba6d0c..94e19d933 100644 --- a/examples/PySDM_examples/Pyrcel/paraview.ipynb +++ b/examples/PySDM_examples/Pyrcel/paraview.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "6dcbcc6d", "metadata": {}, "outputs": [ @@ -42,14 +42,14 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 11, "id": "cd6288b5", "metadata": {}, "outputs": [], "source": [ "settings = Settings(\n", " dz=10 * si.m,\n", - " n_sd_per_mode=(1, 1),\n", + " n_sd_per_mode=(25, 25),\n", " aerosol_modes_by_kappa={\n", " 0.54: Lognormal(norm_factor=850 / si.cm**3, m_mode=15 * si.nm, s_geom=1.6),\n", " 1.2: Lognormal(norm_factor=10 / si.cm**3, m_mode=850 * si.nm, s_geom=1.2),\n", @@ -57,7 +57,7 @@ " vertical_velocity=1.0 * si.m / si.s,\n", " initial_pressure=775 * si.mbar,\n", " initial_temperature=274 * si.K,\n", - " initial_relative_humidity=0.98,\n", + " initial_relative_humidity=0.90,\n", " displacement=1000 * si.m,\n", " formulae=Formulae(constants={\"MAC\": 0.3}),\n", ")\n", @@ -85,7 +85,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 12, "id": "3ff50a25", "metadata": {}, "outputs": [], @@ -95,125 +95,25 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 13, "id": "15d59657", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000000.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000001.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000002.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000003.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000004.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000005.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000006.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000007.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000008.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000009.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000010.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000011.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000012.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000013.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000014.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000015.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000016.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000017.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000018.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000019.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000020.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000021.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000022.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000023.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000024.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000025.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000026.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000027.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000028.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000029.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000030.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000031.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000032.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000033.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000034.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000035.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000036.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000037.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000038.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000039.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000040.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000041.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000042.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000043.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000044.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000045.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000046.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000047.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000048.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000049.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000050.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000051.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000052.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000053.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000054.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000055.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000056.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000057.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000058.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000059.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000060.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000061.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000062.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000063.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000064.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000065.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000066.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000067.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000068.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000069.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000070.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000071.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000072.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000073.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000074.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000075.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000076.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000077.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000078.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000079.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000080.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000081.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000082.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000083.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000084.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000085.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000086.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000087.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000088.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000089.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000090.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000091.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000092.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000093.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000094.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000095.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000096.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000097.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000098.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000099.vtu\n", - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes_num0000000100.vtu\n" - ] - } - ], + "outputs": [], "source": [ - "e = VTKExporterPyrcel(n_sd=simulation.particulator.n_sd)\n", + "e = VTKExporterPyrcel(n_sd=simulation.particulator.n_sd, output=output, mass_of_dry_air=simulation.particulator.environment.mass_of_dry_air)\n", "for step in settings.output_steps:\n", - " e.export_products(output, step, simulation)\n", - " e.export_attributes(output, step, simulation)\n", + " e.export_products(step, simulation)\n", + " e.export_attributes(step, simulation)\n", "e.write_pvd()" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a6ea0e6", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/examples/PySDM_examples/Pyrcel/paraview_simulation.py b/examples/PySDM_examples/Pyrcel/paraview_simulation.py new file mode 100644 index 000000000..77cfb214f --- /dev/null +++ b/examples/PySDM_examples/Pyrcel/paraview_simulation.py @@ -0,0 +1,221 @@ +# to run pvpython script use command line: pvpython filename.py +from paraview import simple as pvs # Updated import statement + +#### disable automatic camera reset on 'Show' +pvs._DisableFirstRenderCameraReset() + +# create a new 'PVD Reader' +sd_productspvd = pvs.PVDReader( + registrationName="sd_products.pvd", + FileName="C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_products.pvd", +) + +# get animation scene +animationScene1 = pvs.GetAnimationScene() + +# update animation scene based on data timesteps +animationScene1.UpdateAnimationUsingDataTimeSteps() + +# get active view +renderView1 = pvs.GetActiveViewOrCreate("RenderView") + +# show data in view +sd_productspvdDisplay = pvs.Show( + sd_productspvd, renderView1, "UnstructuredGridRepresentation" +) + +# trace defaults for the display properties. +sd_productspvdDisplay.Representation = "Surface" + +# reset view to fit data +renderView1.ResetCamera(False, 0.9) + +# show color bar/color legend +sd_productspvdDisplay.SetScalarBarVisibility(renderView1, True) + +# get color transfer function/color map for 'RH' +rHLUT = pvs.GetColorTransferFunction("RH") + +# get opacity transfer function/opacity map for 'RH' +rHPWF = pvs.GetOpacityTransferFunction("RH") + +# get 2D transfer function for 'RH' +rHTF2D = pvs.GetTransferFunction2D("RH") + +# create a new 'PVD Reader' +sd_attributespvd = pvs.PVDReader( + registrationName="sd_attributes.pvd", + FileName="C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes.pvd", +) + +# show data in view +sd_attributespvdDisplay = pvs.Show( + sd_attributespvd, renderView1, "UnstructuredGridRepresentation" +) + +# trace defaults for the display properties. +sd_attributespvdDisplay.Representation = "Surface" + +# show color bar/color legend +sd_attributespvdDisplay.SetScalarBarVisibility(renderView1, True) + +# get color transfer function/color map for 'volume' +volumeLUT = pvs.GetColorTransferFunction("volume") + +# get opacity transfer function/opacity map for 'volume' +volumePWF = pvs.GetOpacityTransferFunction("volume") + +# get 2D transfer function for 'volume' +volumeTF2D = pvs.GetTransferFunction2D("volume") + +# get color legend/bar for rHLUT in view renderView1 +rHLUTColorBar = pvs.GetScalarBar(rHLUT, renderView1) + +# Properties modified on rHLUTColorBar +rHLUTColorBar.LabelColor = [0.0, 0.0, 0.16000610360875867] +rHLUTColorBar.DrawScalarBarOutline = 1 +rHLUTColorBar.ScalarBarOutlineColor = [0.0, 0.0, 0.0] +rHLUTColorBar.TitleColor = [0.0, 0.0, 0.0] + +# Rescale transfer function +rHLUT.RescaleTransferFunction(90.0, 101.0) + +# Rescale transfer function +rHPWF.RescaleTransferFunction(90.0, 101.0) + +# Rescale 2D transfer function +rHTF2D.RescaleTransferFunction(90.0, 101.0, 0.0, 1.0) + +# Properties modified on sd_productspvdDisplay +sd_productspvdDisplay.Opacity = 0.4 + +# Properties modified on sd_productspvdDisplay +sd_productspvdDisplay.DisableLighting = 1 + +# Properties modified on sd_productspvdDisplay +sd_productspvdDisplay.Diffuse = 0.76 + +# Properties modified on sd_productspvdDisplay.DataAxesGrid +sd_productspvdDisplay.DataAxesGrid.GridAxesVisibility = 1 + +# Properties modified on sd_productspvdDisplay.DataAxesGrid +sd_productspvdDisplay.DataAxesGrid.XTitle = "" +sd_productspvdDisplay.DataAxesGrid.YTitle = "" +sd_productspvdDisplay.DataAxesGrid.ZTitle = "" +sd_productspvdDisplay.DataAxesGrid.GridColor = [0.0, 0.0, 0.0] +sd_productspvdDisplay.DataAxesGrid.ShowGrid = 1 +sd_productspvdDisplay.DataAxesGrid.LabelUniqueEdgesOnly = 0 +sd_productspvdDisplay.DataAxesGrid.XAxisUseCustomLabels = 1 +sd_productspvdDisplay.DataAxesGrid.YAxisUseCustomLabels = 1 +sd_productspvdDisplay.DataAxesGrid.ZAxisUseCustomLabels = 1 + +# Properties modified on renderView1 +renderView1.OrientationAxesLabelColor = [0.0, 0.0, 0.16000610360875867] + +# Properties modified on renderView1 +renderView1.OrientationAxesOutlineColor = [0.0, 0.0, 0.16000610360875867] + +# Properties modified on renderView1 +renderView1.OrientationAxesXVisibility = 0 + +# Properties modified on renderView1 +renderView1.OrientationAxesYVisibility = 0 + +# Properties modified on renderView1 +renderView1.OrientationAxesZColor = [0.0, 0.0, 0.0] + +# Properties modified on renderView1 +renderView1.UseColorPaletteForBackground = 0 + +# Properties modified on renderView1 +renderView1.Background = [1.0, 1.0, 1.0] + +# Apply a preset using its name. Note this may not work as expected when presets have duplicate names. +rHLUT.ApplyPreset("Black, Blue and White", True) + +# Properties modified on rHLUT +rHLUT.NanColor = [0.6666666666666666, 1.0, 1.0] + +# change scalar bar placement +rHLUTColorBar.Position = [0.9163059163059163, 0.010638297872340425] +# get color legend/bar for volumeLUT in view renderView1 +volumeLUTColorBar = pvs.GetScalarBar(volumeLUT, renderView1) + +# Properties modified on volumeLUTColorBar +volumeLUTColorBar.LabelColor = [0.0, 0.0, 0.0] +volumeLUTColorBar.DrawScalarBarOutline = 1 +volumeLUTColorBar.ScalarBarOutlineColor = [0.0, 0.0, 0.0] +volumeLUTColorBar.TitleColor = [0.0, 0.0, 0.0] + +# Rescale transfer function +volumeLUT.RescaleTransferFunction(1e-18, 1e-13) + +# Rescale transfer function +volumePWF.RescaleTransferFunction(1e-18, 1e-13) + +# Rescale 2D transfer function +volumeTF2D.RescaleTransferFunction(1e-18, 1e-13, 0.0, 1.0) + +# Properties modified on sd_attributespvdDisplay +sd_attributespvdDisplay.PointSize = 13.0 + +# Properties modified on sd_attributespvdDisplay +sd_attributespvdDisplay.RenderPointsAsSpheres = 1 + +# Properties modified on sd_attributespvdDisplay +sd_attributespvdDisplay.Interpolation = "PBR" + +# Properties modified on sd_attributespvdDisplay.DataAxesGrid +sd_attributespvdDisplay.DataAxesGrid.GridAxesVisibility = 1 + +# Properties modified on sd_attributespvdDisplay.DataAxesGrid +sd_attributespvdDisplay.DataAxesGrid.XTitle = "" +sd_attributespvdDisplay.DataAxesGrid.YTitle = "" +sd_attributespvdDisplay.DataAxesGrid.ZTitle = "Z [m]" +sd_attributespvdDisplay.DataAxesGrid.ZLabelColor = [0.0, 0.0, 0.0] +sd_attributespvdDisplay.DataAxesGrid.ZTitleColor = [0.0, 0.0, 0.0] +sd_attributespvdDisplay.DataAxesGrid.XAxisUseCustomLabels = 1 +sd_attributespvdDisplay.DataAxesGrid.YAxisUseCustomLabels = 1 + +# Apply a preset using its name. Note this may not work as expected when presets have duplicate names. +volumeLUT.ApplyPreset("Cold and Hot", True) + +# convert to log space +volumeLUT.MapControlPointsToLogSpace() + +# Properties modified on volumeLUT +volumeLUT.UseLogScale = 1 + +# Properties modified on volumeLUT +volumeLUT.NumberOfTableValues = 16 + +# invert the transfer function +volumeLUT.InvertTransferFunction() + +# change scalar bar placement +volumeLUTColorBar.Position = [0.9199134199134199, 0.6586879432624113] + +layout1 = pvs.GetLayout() +layout1.SetSize(1593, 1128) +# current camera placement for renderView1 +renderView1.CameraPosition = [1548.945972263949, -1349.493616194682, 699.2699178747185] +renderView1.CameraFocalPoint = [ + -1.3686701146742275e-13, + 3.1755031232028544e-13, + 505.00000000000017, +] +renderView1.CameraViewUp = [ + -0.07221292769632315, + 0.06043215330151439, + 0.9955567527373153, +] +renderView1.CameraParallelScale = 534.07781536883 + +output_animation_path = "C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output_animation.mp4" # Change the extension as needed +output_screenshot_path = ( + "C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\last_frame.png" +) +pvs.SaveAnimation( + output_animation_path, renderView1, FrameRate=15 +) # Adjust FrameRate as needed +pvs.SaveScreenshot(output_screenshot_path, renderView1) diff --git a/examples/PySDM_examples/Pyrcel/simulation.py b/examples/PySDM_examples/Pyrcel/simulation.py index 555b35d89..bdb1d4723 100644 --- a/examples/PySDM_examples/Pyrcel/simulation.py +++ b/examples/PySDM_examples/Pyrcel/simulation.py @@ -27,7 +27,7 @@ def __init__( initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio, T0=settings.initial_temperature, w=settings.vertical_velocity, - mass_of_dry_air=44 * si.kg, + mass_of_dry_air=66666 * si.kg, ), ) builder.add_dynamic(AmbientThermodynamics()) diff --git a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py new file mode 100644 index 000000000..ade9b36f8 --- /dev/null +++ b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py @@ -0,0 +1,343 @@ +#!/usr/bin/env pvpython +import argparse +from collections import namedtuple +import pathlib + +from paraview import simple as pvs # pylint: disable=import-error + +pvs._DisableFirstRenderCameraReset() + + +def cli_using_argparse(argp): + argp.add_argument("product_path", help="path to pvd products file") + argp.add_argument("attributes_path", help=" path to pvd attributes file") + argp.add_argument("output_path", help="path where to write output files") + argp.add_argument( + "--mode", + choices=["light", "dark"], + default="light", + help="Choose 'light' or 'dark' mode.", + ) + argp.add_argument( + "--multiplicity_preset", + default="Inferno (matplotlib)", + help="Preset for multiplicity", + ) + argp.add_argument( + "--multiplicity_logscale", + action="store_false", + help="Use log scale for multiplicity", + ) + argp.add_argument( + "--effectiveradius_preset", + default="Black, Blue and White", + help="Preset for effectiveradius", + ) + argp.add_argument( + "--effectiveradius_logscale", + action="store_false", + help="Use log scale for effectiveradius", + ) + argp.add_argument( + "--effectiveradius_nan_color", + nargs=3, + type=float, + default=[0.666, 0.333, 1.0], + help="Nan color in RGB format for effectiveradius", + ) + argp.add_argument( + "--sd_products_opacity", type=float, default=0.0, help="Opacity for sd_products" + ) + argp.add_argument( + "--calculator1_opacity", + type=float, + default=0.0, + help="Opacity for calculator1", + ) + argp.add_argument( + "--sd_attributes_opacity", + type=float, + default=0.0, + help="Opacity for sd_attributes", + ) + argp.add_argument( + "--animation_size", + nargs=2, + type=int, + default=[800, 800], + help="Animation size [x,y]", + ) + argp.add_argument( + "--animationframename", + type=str, + help="Name of the file with animation last frame", + ) + argp.add_argument( + "--animationname", + type=str, + help="Name of the file with animation", + ) + argp.add_argument( + "--framerate", type=int, help="Number of frame rates.", default=15 + ) + + +ap = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) +cli_using_argparse(ap) + +args = ap.parse_args() +sd_productspvd = pvs.OpenDataFile(args.product_path) +sd_attributespvd = pvs.OpenDataFile(args.attributes_path) + + +setup = { + "renderView1": pvs.GetActiveViewOrCreate("RenderView"), + "sd_attributespvdDisplay": pvs.GetDisplayProperties( + sd_attributespvd, view=pvs.GetActiveViewOrCreate("RenderView") + ), + "effectiveradiusLUT": pvs.GetColorTransferFunction("effectiveradius"), + "sd_productspvdDisplay": pvs.GetDisplayProperties( + sd_productspvd, view=pvs.GetActiveViewOrCreate("RenderView") + ), + "color": [1, 1, 1] if args.mode == "dark" else [0, 0, 0], + "inverted_color": [0.129, 0.145, 0.161] if args.mode == "dark" else [1, 1, 1], +} + +setup = namedtuple("Setup", setup.keys())(**setup) + +setup.effectiveradiusLUT.RescaleTransferFunction(0.1380997175392798, 207.7063518856934) +materialLibrary1 = pvs.GetMaterialLibrary() +setup.renderView1.Update() + + +def create_new_calculator( + calcinput, + representation, + function, + color_by1, + color_by2, + color_by3, + scalar_coloring=False, + hide=False, + *, + y, + registrationame, +): + calculator = pvs.Calculator(registrationName=registrationame, Input=calcinput) + display = pvs.Show(calculator, y.renderView1, representation) + calculator.Function = function + y.renderView1.Update() + if scalar_coloring is True: + pvs.ColorBy(display, (color_by1, color_by2, color_by3)) + if hide is True: + pvs.Hide(calculator, y.renderView1) + return y.renderView1.Update() + + +def scalar_bar(name, *, y, erLUT): + calculator1Display = pvs.Show( + calculator1, y.renderView1, "UnstructuredGridRepresentation" + ) + calculator1Display.SetScalarBarVisibility(y.renderView1, True) + scalarBar = pvs.GetScalarBar(erLUT.effectiveradiusLUT, y.renderView1) + scalarBar.ComponentTitle = "" + scalarBar.Title = name + scalarBar.TitleFontSize = 25 + scalarBar.LabelFontSize = 25 + scalarBar.LabelColor = setup.color + scalarBar.TitleColor = setup.color + pvs.Hide(scalarBar) + y.renderView1.Update() + + +def create_glyph( + registration_name, put, scale_array1, scale_array2, color_by=False, *, y +): + glyph = pvs.Glyph(registrationName=registration_name, Input=put, GlyphType="Arrow") + glyphDisplay = pvs.Show(glyph, y.renderView1, "GeometryRepresentation") + glyphDisplay.Representation = "Surface" + glyph.ScaleArray = [scale_array1, scale_array2] + glyph.ScaleFactor = 100 + glyphDisplay.SetScalarBarVisibility(y.renderView1, True) + multiplicityLUT = pvs.GetColorTransferFunction("multiplicity") + multiplicityLUTColorBar = pvs.GetScalarBar(multiplicityLUT, y.renderView1) + multiplicityLUTColorBar.Position = [0.8, 0.5] + multiplicityLUTColorBar.TitleFontSize = 25 + multiplicityLUTColorBar.LabelFontSize = 25 + multiplicityLUTColorBar.LabelColor = setup.color + multiplicityLUTColorBar.TitleColor = setup.color + if color_by is True: + glyphDisplay.ColorArrayName = ["POINTS", ""] + pvs.ColorBy(glyphDisplay, None) + y.renderView1.Update() + + +def apply_presets_logscale_opacity_and_update(*, y, attdisplay, erLUT, proddisplay): + multiplicityLUT = pvs.GetColorTransferFunction("multiplicity") + multiplicityLUT.RescaleTransferFunction(19951.0, 50461190157.0) + calculator1Display = pvs.Show( + calculator1, y.renderView1, "UnstructuredGridRepresentation" + ) + multiplicityLUT.ApplyPreset(args.multiplicity_preset, True) + if args.multiplicity_logscale: + multiplicityLUT.MapControlPointsToLogSpace() + multiplicityLUT.UseLogScale = 1 + else: + multiplicityLUT.MapControlPointsToLinearSpace() + multiplicityLUT.UseLogScale = 0 + + erLUT.effectiveradiusLUT.ApplyPreset(args.effectiveradius_preset, True) + if args.effectiveradius_logscale: + erLUT.effectiveradiusLUT.MapControlPointsToLogSpace() + erLUT.effectiveradiusLUT.UseLogScale = 1 + else: + erLUT.effectiveradiusLUT.MapControlPointsToLinearSpace() + erLUT.effectiveradiusLUT.UseLogScale = 0 + + erLUT.effectiveradiusLUT.NanColor = args.effectiveradius_nan_color + # proddisplay.sd_productspvdDisplay.SetRepresentationType("Surface With Edges") + proddisplay.sd_productspvdDisplay.Opacity = args.sd_products_opacity + proddisplay.sd_productspvdDisplay.SetScalarBarVisibility(y.renderView1, False) + calculator1Display.Opacity = args.calculator1_opacity + attdisplay.sd_attributespvdDisplay.Opacity = args.sd_attributes_opacity + y.renderView1.Update() + + +def get_layout(*, y): + pvs.SetViewProperties( + Background=setup.inverted_color, UseColorPaletteForBackground=0 + ) + pvs.Render(setup.renderView1) + layout1 = pvs.GetLayout() + layout1.SetSize(args.animation_size) + layout1.PreviewMode = args.animation_size + y.renderView1.Update() + + +def set_current_camera_placement(*, y): + y.renderView1.InteractionMode = "2D" + y.renderView1.CameraPosition = [ + 836, + 677, + -4098, + ] + y.renderView1.CameraFocalPoint = [636, 1030, 0.0] + y.renderView1.CameraViewUp = [1.0, 0.0, 0.0] + y.renderView1.CameraParallelScale = 1560 + y.renderView1.Update() + + +def axes_settings(*, view): + # setup.renderView1.Background = [1,0.5,0.2] + view.CenterAxesVisibility = True + view.OrientationAxesVisibility = False + axesGrid = view.AxesGrid + axesGrid.Visibility = True + axesGrid.XTitle = "Z [m]" + axesGrid.YTitle = "X [m]" + + axesGrid.XAxisUseCustomLabels = True + axesGrid.XAxisLabels = [300, 600, 900, 1200] + axesGrid.YAxisUseCustomLabels = True + axesGrid.YAxisLabels = [300, 600, 900, 1200] + + axesGrid.XTitleFontSize = 30 + axesGrid.XLabelFontSize = 30 + axesGrid.YTitleFontSize = 30 + axesGrid.YLabelFontSize = 30 + + axesGrid.XTitleColor = setup.color + axesGrid.XLabelColor = setup.color + axesGrid.YTitleColor = setup.color + axesGrid.YLabelColor = setup.color + axesGrid.GridColor = [0.1, 0.1, 0.1] + view.CenterAxesVisibility = False + view.Update() + + +def time_annotation(*, y): + time = pvs.AnnotateTimeFilter( + guiName="AnnotateTimeFilter1", Scale=1 / 60, Format="Time:{time:g}min" + ) + timedisplay = pvs.Show(time, y.renderView1) + timedisplay.FontSize = 25 + timedisplay.WindowLocation = "Any Location" + timedisplay.FontSize = 30 + timedisplay.Position = [0.4, 0.9] + timedisplay.Color = setup.color + y.renderView1.Update() + + +def text(text_in, position_y, *, view): + sentence = pvs.Text() + sentence.Text = text_in + textDisplay = pvs.Show(sentence, view) + textDisplay.Color = setup.color + textDisplay.WindowLocation = "Any Location" + textDisplay.FontSize = 28 + textDisplay.Position = [0.17, position_y] + + +def last_anim_frame(animation_frame_name): + time_steps = sd_productspvd.TimestepValues + last_time = time_steps[90] + setup.renderView1.ViewTime = last_time + for reader in (sd_productspvd,): + reader.UpdatePipeline(last_time) + pvs.ExportView( + filename=str(pathlib.Path(args.output_path) / animation_frame_name), + view=setup.renderView1, + Rasterize3Dgeometry=False, + GL2PSdepthsortmethod="BSP sorting (slow, best)", + ) + pvs.RenderAllViews() + + +calculator1 = create_new_calculator( + sd_attributespvd, + "UnstructuredGridRepresentation", + '"relative fall velocity"*(-iHat)', + "None", + "None", + "None", + y=setup, + registrationame="Calculator1", +) +# scalar_bar("effective radius [um]", y=setup, erLUT=setup) +glyph1 = create_glyph( + "Glyph1", calculator1, "POINTS", "relative fall velocity", y=setup +) +pvs.Hide(glyph1) +"""calculator2 = create_new_calculator( + sd_productspvd, + "StructuredGridRepresentation", + "cx*jHat+cy*iHat", + "CELLS", + "Result", + "Magnitude", + True, + True, + y=setup, + registrationame="Calculator2", +)""" +# pvs.Hide(calculator2) +apply_presets_logscale_opacity_and_update( + y=setup, attdisplay=setup, erLUT=setup, proddisplay=setup +) +# glyph2 = create_glyph("Glyph2", calculator2, "CELLS", "Result", True, y=setup) +# pvs.Hide(glyph2) +get_layout(y=setup) +set_current_camera_placement(y=setup) +axes_settings(view=setup.renderView1) +time_annotation(y=setup) +if args.animationframename is not None: + last_anim_frame(animation_frame_name=args.animationframename) +scene = pvs.GetAnimationScene() +scene.UpdateAnimationUsingDataTimeSteps() +pvs.Render(setup.renderView1) +pvs.SaveAnimation( + str(pathlib.Path(args.output_path) / args.animationname), + setup.renderView1, + FrameRate=args.framerate, +) +pvs.RenderAllViews() diff --git a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py new file mode 100644 index 000000000..803819ecb --- /dev/null +++ b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py @@ -0,0 +1,341 @@ +#!/usr/bin/env pvpython +import argparse +from collections import namedtuple +import pathlib + +from paraview import simple as pvs # pylint: disable=import-error + +pvs._DisableFirstRenderCameraReset() + + +def cli_using_argparse(argp): + argp.add_argument("product_path", help="path to pvd products file") + argp.add_argument("attributes_path", help=" path to pvd attributes file") + argp.add_argument("output_path", help="path where to write output files") + argp.add_argument( + "--mode", + choices=["light", "dark"], + default="dark", + help="Choose 'light' or 'dark' mode.", + ) + argp.add_argument( + "--multiplicity_preset", + default="Inferno (matplotlib)", + help="Preset for multiplicity", + ) + argp.add_argument( + "--multiplicity_logscale", + action="store_false", + help="Use log scale for multiplicity", + ) + argp.add_argument( + "--effectiveradius_preset", + default="Black, Blue and White", + help="Preset for effectiveradius", + ) + argp.add_argument( + "--effectiveradius_logscale", + action="store_false", + help="Use log scale for effectiveradius", + ) + argp.add_argument( + "--effectiveradius_nan_color", + nargs=3, + type=float, + default=[0.666, 0.333, 1.0], + help="Nan color in RGB format for effectiveradius", + ) + argp.add_argument( + "--sd_products_opacity", type=float, default=0.9, help="Opacity for sd_products" + ) + argp.add_argument( + "--calculator1_opacity", + type=float, + default=0.19, + help="Opacity for calculator1", + ) + argp.add_argument( + "--sd_attributes_opacity", + type=float, + default=0.77, + help="Opacity for sd_attributes", + ) + argp.add_argument( + "--animation_size", + nargs=2, + type=int, + default=[800, 800], + help="Animation size [x,y]", + ) + argp.add_argument( + "--animationframename", + type=str, + help="Name of the file with animation last frame", + ) + argp.add_argument( + "--animationname", + type=str, + help="Name of the file with animation", + ) + argp.add_argument( + "--framerate", type=int, help="Number of frame rates.", default=15 + ) + + +ap = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) +cli_using_argparse(ap) + +args = ap.parse_args() +sd_productspvd = pvs.OpenDataFile(args.product_path) +sd_attributespvd = pvs.OpenDataFile(args.attributes_path) + + +setup = { + "renderView1": pvs.GetActiveViewOrCreate("RenderView"), + "sd_attributespvdDisplay": pvs.GetDisplayProperties( + sd_attributespvd, view=pvs.GetActiveViewOrCreate("RenderView") + ), + "effectiveradiusLUT": pvs.GetColorTransferFunction("effectiveradius"), + "sd_productspvdDisplay": pvs.GetDisplayProperties( + sd_productspvd, view=pvs.GetActiveViewOrCreate("RenderView") + ), + "color": [1, 1, 1] if args.mode == "dark" else [0, 0, 0], + "inverted_color": [0.129, 0.145, 0.161] if args.mode == "dark" else [1, 1, 1], +} + +setup = namedtuple("Setup", setup.keys())(**setup) + +setup.effectiveradiusLUT.RescaleTransferFunction(0.1380997175392798, 207.7063518856934) +materialLibrary1 = pvs.GetMaterialLibrary() +setup.renderView1.Update() + + +def create_new_calculator( + calcinput, + representation, + function, + color_by1, + color_by2, + color_by3, + scalar_coloring=False, + hide=False, + *, + y, + registrationame, +): + calculator = pvs.Calculator(registrationName=registrationame, Input=calcinput) + display = pvs.Show(calculator, y.renderView1, representation) + calculator.Function = function + y.renderView1.Update() + if scalar_coloring is True: + pvs.ColorBy(display, (color_by1, color_by2, color_by3)) + if hide is True: + pvs.Hide(calculator, y.renderView1) + return y.renderView1.Update() + + +def scalar_bar(name, *, y, erLUT): + calculator1Display = pvs.Show( + calculator1, y.renderView1, "UnstructuredGridRepresentation" + ) + calculator1Display.SetScalarBarVisibility(y.renderView1, True) + scalarBar = pvs.GetScalarBar(erLUT.effectiveradiusLUT, y.renderView1) + scalarBar.ComponentTitle = "" + scalarBar.Title = name + scalarBar.TitleFontSize = 25 + scalarBar.LabelFontSize = 25 + scalarBar.LabelColor = setup.color + scalarBar.TitleColor = setup.color + y.renderView1.Update() + + +def create_glyph( + registration_name, put, scale_array1, scale_array2, color_by=False, *, y +): + glyph = pvs.Glyph(registrationName=registration_name, Input=put, GlyphType="Arrow") + glyphDisplay = pvs.Show(glyph, y.renderView1, "GeometryRepresentation") + glyphDisplay.Representation = "Surface" + glyph.ScaleArray = [scale_array1, scale_array2] + glyph.ScaleFactor = 100 + glyphDisplay.SetScalarBarVisibility(y.renderView1, True) + multiplicityLUT = pvs.GetColorTransferFunction("multiplicity") + multiplicityLUTColorBar = pvs.GetScalarBar(multiplicityLUT, y.renderView1) + multiplicityLUTColorBar.TitleFontSize = 25 + multiplicityLUTColorBar.LabelFontSize = 25 + multiplicityLUTColorBar.LabelColor = setup.color + multiplicityLUTColorBar.TitleColor = setup.color + if color_by is True: + glyphDisplay.ColorArrayName = ["POINTS", ""] + pvs.ColorBy(glyphDisplay, None) + y.renderView1.Update() + + +def apply_presets_logscale_opacity_and_update(*, y, attdisplay, erLUT, proddisplay): + multiplicityLUT = pvs.GetColorTransferFunction("multiplicity") + multiplicityLUT.RescaleTransferFunction(19951.0, 50461190157.0) + calculator1Display = pvs.Show( + calculator1, y.renderView1, "UnstructuredGridRepresentation" + ) + multiplicityLUT.ApplyPreset(args.multiplicity_preset, True) + if args.multiplicity_logscale: + multiplicityLUT.MapControlPointsToLogSpace() + multiplicityLUT.UseLogScale = 1 + else: + multiplicityLUT.MapControlPointsToLinearSpace() + multiplicityLUT.UseLogScale = 0 + + erLUT.effectiveradiusLUT.ApplyPreset(args.effectiveradius_preset, True) + if args.effectiveradius_logscale: + erLUT.effectiveradiusLUT.MapControlPointsToLogSpace() + erLUT.effectiveradiusLUT.UseLogScale = 1 + else: + erLUT.effectiveradiusLUT.MapControlPointsToLinearSpace() + erLUT.effectiveradiusLUT.UseLogScale = 0 + + erLUT.effectiveradiusLUT.NanColor = args.effectiveradius_nan_color + + proddisplay.sd_productspvdDisplay.SetRepresentationType("Surface With Edges") + proddisplay.sd_productspvdDisplay.Opacity = args.sd_products_opacity + calculator1Display.Opacity = args.calculator1_opacity + attdisplay.sd_attributespvdDisplay.Opacity = args.sd_attributes_opacity + + y.renderView1.Update() + + +def get_layout(*, y): + pvs.SetViewProperties( + Background=setup.inverted_color, UseColorPaletteForBackground=0 + ) + pvs.Render(setup.renderView1) + layout1 = pvs.GetLayout() + layout1.SetSize(args.animation_size) + layout1.PreviewMode = args.animation_size + y.renderView1.Update() + + +def set_current_camera_placement(*, y): + y.renderView1.InteractionMode = "2D" + y.renderView1.CameraPosition = [ + 836, + 677, + -4098, + ] + y.renderView1.CameraFocalPoint = [636, 1030, 0.0] + y.renderView1.CameraViewUp = [1.0, 0.0, 0.0] + y.renderView1.CameraParallelScale = 1560 + y.renderView1.Update() + + +def axes_settings(*, view): + # setup.renderView1.Background = [1,0.5,0.2] + view.CenterAxesVisibility = True + view.OrientationAxesVisibility = False + axesGrid = view.AxesGrid + axesGrid.Visibility = True + axesGrid.XTitle = "Z [m]" + axesGrid.YTitle = "X [m]" + + axesGrid.XAxisUseCustomLabels = True + axesGrid.XAxisLabels = [300, 600, 900, 1200] + axesGrid.YAxisUseCustomLabels = True + axesGrid.YAxisLabels = [300, 600, 900, 1200] + + axesGrid.XTitleFontSize = 30 + axesGrid.XLabelFontSize = 30 + axesGrid.YTitleFontSize = 30 + axesGrid.YLabelFontSize = 30 + + axesGrid.XTitleColor = setup.color + axesGrid.XLabelColor = setup.color + axesGrid.YTitleColor = setup.color + axesGrid.YLabelColor = setup.color + axesGrid.GridColor = [0.1, 0.1, 0.1] + view.CenterAxesVisibility = False + view.Update() + + +def time_annotation(*, y): + time = pvs.AnnotateTimeFilter( + guiName="AnnotateTimeFilter1", Scale=1 / 60, Format="Time:{time:g}min" + ) + timedisplay = pvs.Show(time, y.renderView1) + timedisplay.FontSize = 25 + timedisplay.WindowLocation = "Any Location" + timedisplay.FontSize = 30 + timedisplay.Position = [0.4, 0.9] + timedisplay.Color = setup.color + y.renderView1.Update() + + +def text(text_in, position_y, *, view): + sentence = pvs.Text() + sentence.Text = text_in + textDisplay = pvs.Show(sentence, view) + textDisplay.Color = setup.color + textDisplay.WindowLocation = "Any Location" + textDisplay.FontSize = 28 + textDisplay.Position = [0.17, position_y] + + +def last_anim_frame(animation_frame_name): + time_steps = sd_productspvd.TimestepValues + last_time = time_steps[90] + setup.renderView1.ViewTime = last_time + for reader in (sd_productspvd,): + reader.UpdatePipeline(last_time) + pvs.ExportView( + filename=str(pathlib.Path(args.output_path) / animation_frame_name), + view=setup.renderView1, + Rasterize3Dgeometry=False, + GL2PSdepthsortmethod="BSP sorting (slow, best)", + ) + pvs.RenderAllViews() + + +calculator1 = create_new_calculator( + sd_attributespvd, + "UnstructuredGridRepresentation", + '"relative fall velocity"*(-iHat)', + "None", + "None", + "None", + y=setup, + registrationame="Calculator1", +) +scalar_bar("effective radius [um]", y=setup, erLUT=setup) +glyph1 = create_glyph( + "Glyph1", calculator1, "POINTS", "relative fall velocity", y=setup +) +pvs.Hide(glyph1) +calculator2 = create_new_calculator( + sd_productspvd, + "StructuredGridRepresentation", + "cx*jHat+cy*iHat", + "CELLS", + "Result", + "Magnitude", + True, + True, + y=setup, + registrationame="Calculator2", +) +apply_presets_logscale_opacity_and_update( + y=setup, attdisplay=setup, erLUT=setup, proddisplay=setup +) +glyph2 = create_glyph("Glyph2", calculator2, "CELLS", "Result", True, y=setup) +pvs.Hide(glyph2) +get_layout(y=setup) +set_current_camera_placement(y=setup) +axes_settings(view=setup.renderView1) +time_annotation(y=setup) +if args.animationframename is not None: + last_anim_frame(animation_frame_name=args.animationframename) +scene = pvs.GetAnimationScene() +scene.UpdateAnimationUsingDataTimeSteps() +pvs.Render(setup.renderView1) +pvs.SaveAnimation( + str(pathlib.Path(args.output_path) / args.animationname), + setup.renderView1, + FrameRate=args.framerate, +) +pvs.RenderAllViews() From 51f70813d100cfb8daa5aa9125f3255f4df3abde Mon Sep 17 00:00:00 2001 From: olastrz Date: Sun, 5 Oct 2025 21:39:18 +0200 Subject: [PATCH 04/29] new paraview_sim update --- .../Pyrcel/paraview_simulation.py | 143 ++++-------------- 1 file changed, 26 insertions(+), 117 deletions(-) diff --git a/examples/PySDM_examples/Pyrcel/paraview_simulation.py b/examples/PySDM_examples/Pyrcel/paraview_simulation.py index 77cfb214f..4ad22beb5 100644 --- a/examples/PySDM_examples/Pyrcel/paraview_simulation.py +++ b/examples/PySDM_examples/Pyrcel/paraview_simulation.py @@ -1,104 +1,51 @@ # to run pvpython script use command line: pvpython filename.py from paraview import simple as pvs # Updated import statement -#### disable automatic camera reset on 'Show' pvs._DisableFirstRenderCameraReset() -# create a new 'PVD Reader' +# get active view +renderView1 = pvs.GetActiveViewOrCreate("RenderView") + +# show data in view prod sd_productspvd = pvs.PVDReader( registrationName="sd_products.pvd", FileName="C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_products.pvd", ) - -# get animation scene -animationScene1 = pvs.GetAnimationScene() - -# update animation scene based on data timesteps -animationScene1.UpdateAnimationUsingDataTimeSteps() - -# get active view -renderView1 = pvs.GetActiveViewOrCreate("RenderView") - -# show data in view sd_productspvdDisplay = pvs.Show( sd_productspvd, renderView1, "UnstructuredGridRepresentation" ) - -# trace defaults for the display properties. sd_productspvdDisplay.Representation = "Surface" - -# reset view to fit data -renderView1.ResetCamera(False, 0.9) - -# show color bar/color legend sd_productspvdDisplay.SetScalarBarVisibility(renderView1, True) - -# get color transfer function/color map for 'RH' rHLUT = pvs.GetColorTransferFunction("RH") +rHLUT.RescaleTransferFunction(90.0, 101.0) -# get opacity transfer function/opacity map for 'RH' -rHPWF = pvs.GetOpacityTransferFunction("RH") - -# get 2D transfer function for 'RH' -rHTF2D = pvs.GetTransferFunction2D("RH") - -# create a new 'PVD Reader' +# show data in view attr sd_attributespvd = pvs.PVDReader( registrationName="sd_attributes.pvd", FileName="C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes.pvd", ) - -# show data in view sd_attributespvdDisplay = pvs.Show( sd_attributespvd, renderView1, "UnstructuredGridRepresentation" ) - -# trace defaults for the display properties. sd_attributespvdDisplay.Representation = "Surface" - -# show color bar/color legend sd_attributespvdDisplay.SetScalarBarVisibility(renderView1, True) - -# get color transfer function/color map for 'volume' volumeLUT = pvs.GetColorTransferFunction("volume") - -# get opacity transfer function/opacity map for 'volume' -volumePWF = pvs.GetOpacityTransferFunction("volume") - -# get 2D transfer function for 'volume' -volumeTF2D = pvs.GetTransferFunction2D("volume") - -# get color legend/bar for rHLUT in view renderView1 -rHLUTColorBar = pvs.GetScalarBar(rHLUT, renderView1) +volumeLUT.RescaleTransferFunction(1e-18, 1e-13) # Properties modified on rHLUTColorBar -rHLUTColorBar.LabelColor = [0.0, 0.0, 0.16000610360875867] +rHLUTColorBar = pvs.GetScalarBar(rHLUT, renderView1) +rHLUTColorBar.LabelColor = [0.0, 0.0, 0.0] rHLUTColorBar.DrawScalarBarOutline = 1 rHLUTColorBar.ScalarBarOutlineColor = [0.0, 0.0, 0.0] rHLUTColorBar.TitleColor = [0.0, 0.0, 0.0] -# Rescale transfer function -rHLUT.RescaleTransferFunction(90.0, 101.0) - -# Rescale transfer function -rHPWF.RescaleTransferFunction(90.0, 101.0) - -# Rescale 2D transfer function -rHTF2D.RescaleTransferFunction(90.0, 101.0, 0.0, 1.0) - -# Properties modified on sd_productspvdDisplay +# lightning and opacity sd_productspvdDisplay sd_productspvdDisplay.Opacity = 0.4 - -# Properties modified on sd_productspvdDisplay sd_productspvdDisplay.DisableLighting = 1 - -# Properties modified on sd_productspvdDisplay sd_productspvdDisplay.Diffuse = 0.76 # Properties modified on sd_productspvdDisplay.DataAxesGrid sd_productspvdDisplay.DataAxesGrid.GridAxesVisibility = 1 - -# Properties modified on sd_productspvdDisplay.DataAxesGrid sd_productspvdDisplay.DataAxesGrid.XTitle = "" sd_productspvdDisplay.DataAxesGrid.YTitle = "" sd_productspvdDisplay.DataAxesGrid.ZTitle = "" @@ -109,66 +56,35 @@ sd_productspvdDisplay.DataAxesGrid.YAxisUseCustomLabels = 1 sd_productspvdDisplay.DataAxesGrid.ZAxisUseCustomLabels = 1 -# Properties modified on renderView1 -renderView1.OrientationAxesLabelColor = [0.0, 0.0, 0.16000610360875867] - -# Properties modified on renderView1 -renderView1.OrientationAxesOutlineColor = [0.0, 0.0, 0.16000610360875867] - -# Properties modified on renderView1 +# orientation axes +renderView1.OrientationAxesLabelColor = [0.0, 0.0, 0.0] +renderView1.OrientationAxesOutlineColor = [0.0, 0.0, 0.0] renderView1.OrientationAxesXVisibility = 0 - -# Properties modified on renderView1 renderView1.OrientationAxesYVisibility = 0 - -# Properties modified on renderView1 renderView1.OrientationAxesZColor = [0.0, 0.0, 0.0] -# Properties modified on renderView1 +# background renderView1.UseColorPaletteForBackground = 0 - -# Properties modified on renderView1 renderView1.Background = [1.0, 1.0, 1.0] -# Apply a preset using its name. Note this may not work as expected when presets have duplicate names. +# rHLUT color rHLUT.ApplyPreset("Black, Blue and White", True) - -# Properties modified on rHLUT rHLUT.NanColor = [0.6666666666666666, 1.0, 1.0] -# change scalar bar placement -rHLUTColorBar.Position = [0.9163059163059163, 0.010638297872340425] -# get color legend/bar for volumeLUT in view renderView1 -volumeLUTColorBar = pvs.GetScalarBar(volumeLUT, renderView1) - # Properties modified on volumeLUTColorBar +volumeLUTColorBar = pvs.GetScalarBar(volumeLUT, renderView1) volumeLUTColorBar.LabelColor = [0.0, 0.0, 0.0] volumeLUTColorBar.DrawScalarBarOutline = 1 volumeLUTColorBar.ScalarBarOutlineColor = [0.0, 0.0, 0.0] volumeLUTColorBar.TitleColor = [0.0, 0.0, 0.0] -# Rescale transfer function -volumeLUT.RescaleTransferFunction(1e-18, 1e-13) - -# Rescale transfer function -volumePWF.RescaleTransferFunction(1e-18, 1e-13) - -# Rescale 2D transfer function -volumeTF2D.RescaleTransferFunction(1e-18, 1e-13, 0.0, 1.0) - -# Properties modified on sd_attributespvdDisplay +# attr size and shape sd_attributespvdDisplay.PointSize = 13.0 - -# Properties modified on sd_attributespvdDisplay sd_attributespvdDisplay.RenderPointsAsSpheres = 1 - -# Properties modified on sd_attributespvdDisplay sd_attributespvdDisplay.Interpolation = "PBR" # Properties modified on sd_attributespvdDisplay.DataAxesGrid sd_attributespvdDisplay.DataAxesGrid.GridAxesVisibility = 1 - -# Properties modified on sd_attributespvdDisplay.DataAxesGrid sd_attributespvdDisplay.DataAxesGrid.XTitle = "" sd_attributespvdDisplay.DataAxesGrid.YTitle = "" sd_attributespvdDisplay.DataAxesGrid.ZTitle = "Z [m]" @@ -177,26 +93,17 @@ sd_attributespvdDisplay.DataAxesGrid.XAxisUseCustomLabels = 1 sd_attributespvdDisplay.DataAxesGrid.YAxisUseCustomLabels = 1 -# Apply a preset using its name. Note this may not work as expected when presets have duplicate names. +# volumeLUT preset and scale volumeLUT.ApplyPreset("Cold and Hot", True) - -# convert to log space volumeLUT.MapControlPointsToLogSpace() - -# Properties modified on volumeLUT volumeLUT.UseLogScale = 1 - -# Properties modified on volumeLUT volumeLUT.NumberOfTableValues = 16 - -# invert the transfer function volumeLUT.InvertTransferFunction() -# change scalar bar placement -volumeLUTColorBar.Position = [0.9199134199134199, 0.6586879432624113] - +# layout layout1 = pvs.GetLayout() layout1.SetSize(1593, 1128) + # current camera placement for renderView1 renderView1.CameraPosition = [1548.945972263949, -1349.493616194682, 699.2699178747185] renderView1.CameraFocalPoint = [ @@ -211,11 +118,13 @@ ] renderView1.CameraParallelScale = 534.07781536883 -output_animation_path = "C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output_animation.mp4" # Change the extension as needed +# get animation scene +animationScene1 = pvs.GetAnimationScene() +animationScene1.UpdateAnimationUsingDataTimeSteps() + +output_animation_path = "C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output_animation.avi" # Change the extension as needed output_screenshot_path = ( "C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\last_frame.png" ) -pvs.SaveAnimation( - output_animation_path, renderView1, FrameRate=15 -) # Adjust FrameRate as needed +pvs.SaveAnimation(output_animation_path, renderView1, FrameRate=15) pvs.SaveScreenshot(output_screenshot_path, renderView1) From 760a2e3d91d8b2fc8560ae95078819045b6328be Mon Sep 17 00:00:00 2001 From: olastrz Date: Wed, 8 Oct 2025 14:55:28 +0200 Subject: [PATCH 05/29] new argparse --- .../Pyrcel/paraview_simulation.py | 58 ++++++++++++------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/examples/PySDM_examples/Pyrcel/paraview_simulation.py b/examples/PySDM_examples/Pyrcel/paraview_simulation.py index 4ad22beb5..5ff47ef56 100644 --- a/examples/PySDM_examples/Pyrcel/paraview_simulation.py +++ b/examples/PySDM_examples/Pyrcel/paraview_simulation.py @@ -1,6 +1,28 @@ -# to run pvpython script use command line: pvpython filename.py +import argparse from paraview import simple as pvs # Updated import statement + +def cli_using_argparse(ap): + ap.add_argument( + "--sd-products-pvd", + dest="sd_products_pvd", + default=r"C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_products.pvd", + help="Path to sd_products.pvd", + ) + ap.add_argument( + "--sd-attributes-pvd", + dest="sd_attributes_pvd", + default=r"C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes.pvd", + help="Path to sd_attributes.pvd", + ) + + +parser = argparse.ArgumentParser( + description="ParaView pvpython script for visualizing sd_products and sd_attributes PVD files." +) +cli_using_argparse(parser) +args = parser.parse_args() + pvs._DisableFirstRenderCameraReset() # get active view @@ -9,7 +31,7 @@ # show data in view prod sd_productspvd = pvs.PVDReader( registrationName="sd_products.pvd", - FileName="C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_products.pvd", + FileName=args.sd_products_pvd, ) sd_productspvdDisplay = pvs.Show( sd_productspvd, renderView1, "UnstructuredGridRepresentation" @@ -22,7 +44,7 @@ # show data in view attr sd_attributespvd = pvs.PVDReader( registrationName="sd_attributes.pvd", - FileName="C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes.pvd", + FileName=args.sd_attributes_pvd, ) sd_attributespvdDisplay = pvs.Show( sd_attributespvd, renderView1, "UnstructuredGridRepresentation" @@ -43,6 +65,8 @@ sd_productspvdDisplay.Opacity = 0.4 sd_productspvdDisplay.DisableLighting = 1 sd_productspvdDisplay.Diffuse = 0.76 +rHLUT.ApplyPreset("Black, Blue and White", True) +rHLUT.NanColor = [0.6666666666666666, 1.0, 1.0] # Properties modified on sd_productspvdDisplay.DataAxesGrid sd_productspvdDisplay.DataAxesGrid.GridAxesVisibility = 1 @@ -67,10 +91,6 @@ renderView1.UseColorPaletteForBackground = 0 renderView1.Background = [1.0, 1.0, 1.0] -# rHLUT color -rHLUT.ApplyPreset("Black, Blue and White", True) -rHLUT.NanColor = [0.6666666666666666, 1.0, 1.0] - # Properties modified on volumeLUTColorBar volumeLUTColorBar = pvs.GetScalarBar(volumeLUT, renderView1) volumeLUTColorBar.LabelColor = [0.0, 0.0, 0.0] @@ -78,10 +98,15 @@ volumeLUTColorBar.ScalarBarOutlineColor = [0.0, 0.0, 0.0] volumeLUTColorBar.TitleColor = [0.0, 0.0, 0.0] -# attr size and shape +# attr size and shape and color etc sd_attributespvdDisplay.PointSize = 13.0 sd_attributespvdDisplay.RenderPointsAsSpheres = 1 sd_attributespvdDisplay.Interpolation = "PBR" +volumeLUT.ApplyPreset("Cold and Hot", True) +volumeLUT.MapControlPointsToLogSpace() +volumeLUT.UseLogScale = 1 +volumeLUT.NumberOfTableValues = 16 +volumeLUT.InvertTransferFunction() # Properties modified on sd_attributespvdDisplay.DataAxesGrid sd_attributespvdDisplay.DataAxesGrid.GridAxesVisibility = 1 @@ -93,18 +118,9 @@ sd_attributespvdDisplay.DataAxesGrid.XAxisUseCustomLabels = 1 sd_attributespvdDisplay.DataAxesGrid.YAxisUseCustomLabels = 1 -# volumeLUT preset and scale -volumeLUT.ApplyPreset("Cold and Hot", True) -volumeLUT.MapControlPointsToLogSpace() -volumeLUT.UseLogScale = 1 -volumeLUT.NumberOfTableValues = 16 -volumeLUT.InvertTransferFunction() - -# layout +# current camera placement for renderView1 and layout layout1 = pvs.GetLayout() -layout1.SetSize(1593, 1128) - -# current camera placement for renderView1 +layout1.SetSize(1592, 1128) renderView1.CameraPosition = [1548.945972263949, -1349.493616194682, 699.2699178747185] renderView1.CameraFocalPoint = [ -1.3686701146742275e-13, @@ -122,9 +138,9 @@ animationScene1 = pvs.GetAnimationScene() animationScene1.UpdateAnimationUsingDataTimeSteps() -output_animation_path = "C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output_animation.avi" # Change the extension as needed +output_animation_path = r"C:\Users\strza\Desktop\PySDM\examples\PySDM_examples\Pyrcel\output_animation.avi" # Change the extension as needed output_screenshot_path = ( - "C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\last_frame.png" + r"C:\Users\strza\Desktop\PySDM\examples\PySDM_examples\Pyrcel\last_frame.png" ) pvs.SaveAnimation(output_animation_path, renderView1, FrameRate=15) pvs.SaveScreenshot(output_screenshot_path, renderView1) From b90d54f6cd402b7d4ba552f9c2acb59445271b41 Mon Sep 17 00:00:00 2001 From: olastrz Date: Wed, 8 Oct 2025 16:20:47 +0200 Subject: [PATCH 06/29] new functions and cosmetic changes --- .../Pyrcel/paraview_simulation.py | 241 ++++++++++-------- 1 file changed, 131 insertions(+), 110 deletions(-) diff --git a/examples/PySDM_examples/Pyrcel/paraview_simulation.py b/examples/PySDM_examples/Pyrcel/paraview_simulation.py index 5ff47ef56..8bd16d025 100644 --- a/examples/PySDM_examples/Pyrcel/paraview_simulation.py +++ b/examples/PySDM_examples/Pyrcel/paraview_simulation.py @@ -1,18 +1,25 @@ +""" +ParaView pvpython script for visualizing sd_products and sd_attributes. +""" + import argparse -from paraview import simple as pvs # Updated import statement +from paraview import simple as pvs # pylint: disable=import-error -def cli_using_argparse(ap): - ap.add_argument( +def cli_using_argparse(argparse_parser): + """ + Command line interface using argparse. + """ + argparse_parser.add_argument( "--sd-products-pvd", dest="sd_products_pvd", - default=r"C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_products.pvd", + default=r"C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_products.pvd", # pylint: disable=line-too-long help="Path to sd_products.pvd", ) - ap.add_argument( + argparse_parser.add_argument( "--sd-attributes-pvd", dest="sd_attributes_pvd", - default=r"C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes.pvd", + default=r"C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes.pvd", # pylint: disable=line-too-long help="Path to sd_attributes.pvd", ) @@ -23,12 +30,9 @@ def cli_using_argparse(ap): cli_using_argparse(parser) args = parser.parse_args() -pvs._DisableFirstRenderCameraReset() - -# get active view +# TODO tuple +pvs._DisableFirstRenderCameraReset() # pylint: disable=protected-access renderView1 = pvs.GetActiveViewOrCreate("RenderView") - -# show data in view prod sd_productspvd = pvs.PVDReader( registrationName="sd_products.pvd", FileName=args.sd_products_pvd, @@ -36,12 +40,6 @@ def cli_using_argparse(ap): sd_productspvdDisplay = pvs.Show( sd_productspvd, renderView1, "UnstructuredGridRepresentation" ) -sd_productspvdDisplay.Representation = "Surface" -sd_productspvdDisplay.SetScalarBarVisibility(renderView1, True) -rHLUT = pvs.GetColorTransferFunction("RH") -rHLUT.RescaleTransferFunction(90.0, 101.0) - -# show data in view attr sd_attributespvd = pvs.PVDReader( registrationName="sd_attributes.pvd", FileName=args.sd_attributes_pvd, @@ -49,98 +47,121 @@ def cli_using_argparse(ap): sd_attributespvdDisplay = pvs.Show( sd_attributespvd, renderView1, "UnstructuredGridRepresentation" ) -sd_attributespvdDisplay.Representation = "Surface" -sd_attributespvdDisplay.SetScalarBarVisibility(renderView1, True) -volumeLUT = pvs.GetColorTransferFunction("volume") -volumeLUT.RescaleTransferFunction(1e-18, 1e-13) - -# Properties modified on rHLUTColorBar -rHLUTColorBar = pvs.GetScalarBar(rHLUT, renderView1) -rHLUTColorBar.LabelColor = [0.0, 0.0, 0.0] -rHLUTColorBar.DrawScalarBarOutline = 1 -rHLUTColorBar.ScalarBarOutlineColor = [0.0, 0.0, 0.0] -rHLUTColorBar.TitleColor = [0.0, 0.0, 0.0] - -# lightning and opacity sd_productspvdDisplay -sd_productspvdDisplay.Opacity = 0.4 -sd_productspvdDisplay.DisableLighting = 1 -sd_productspvdDisplay.Diffuse = 0.76 -rHLUT.ApplyPreset("Black, Blue and White", True) -rHLUT.NanColor = [0.6666666666666666, 1.0, 1.0] - -# Properties modified on sd_productspvdDisplay.DataAxesGrid -sd_productspvdDisplay.DataAxesGrid.GridAxesVisibility = 1 -sd_productspvdDisplay.DataAxesGrid.XTitle = "" -sd_productspvdDisplay.DataAxesGrid.YTitle = "" -sd_productspvdDisplay.DataAxesGrid.ZTitle = "" -sd_productspvdDisplay.DataAxesGrid.GridColor = [0.0, 0.0, 0.0] -sd_productspvdDisplay.DataAxesGrid.ShowGrid = 1 -sd_productspvdDisplay.DataAxesGrid.LabelUniqueEdgesOnly = 0 -sd_productspvdDisplay.DataAxesGrid.XAxisUseCustomLabels = 1 -sd_productspvdDisplay.DataAxesGrid.YAxisUseCustomLabels = 1 -sd_productspvdDisplay.DataAxesGrid.ZAxisUseCustomLabels = 1 - -# orientation axes -renderView1.OrientationAxesLabelColor = [0.0, 0.0, 0.0] -renderView1.OrientationAxesOutlineColor = [0.0, 0.0, 0.0] -renderView1.OrientationAxesXVisibility = 0 -renderView1.OrientationAxesYVisibility = 0 -renderView1.OrientationAxesZColor = [0.0, 0.0, 0.0] - -# background -renderView1.UseColorPaletteForBackground = 0 -renderView1.Background = [1.0, 1.0, 1.0] - -# Properties modified on volumeLUTColorBar -volumeLUTColorBar = pvs.GetScalarBar(volumeLUT, renderView1) -volumeLUTColorBar.LabelColor = [0.0, 0.0, 0.0] -volumeLUTColorBar.DrawScalarBarOutline = 1 -volumeLUTColorBar.ScalarBarOutlineColor = [0.0, 0.0, 0.0] -volumeLUTColorBar.TitleColor = [0.0, 0.0, 0.0] - -# attr size and shape and color etc -sd_attributespvdDisplay.PointSize = 13.0 -sd_attributespvdDisplay.RenderPointsAsSpheres = 1 -sd_attributespvdDisplay.Interpolation = "PBR" -volumeLUT.ApplyPreset("Cold and Hot", True) -volumeLUT.MapControlPointsToLogSpace() -volumeLUT.UseLogScale = 1 -volumeLUT.NumberOfTableValues = 16 -volumeLUT.InvertTransferFunction() - -# Properties modified on sd_attributespvdDisplay.DataAxesGrid -sd_attributespvdDisplay.DataAxesGrid.GridAxesVisibility = 1 -sd_attributespvdDisplay.DataAxesGrid.XTitle = "" -sd_attributespvdDisplay.DataAxesGrid.YTitle = "" -sd_attributespvdDisplay.DataAxesGrid.ZTitle = "Z [m]" -sd_attributespvdDisplay.DataAxesGrid.ZLabelColor = [0.0, 0.0, 0.0] -sd_attributespvdDisplay.DataAxesGrid.ZTitleColor = [0.0, 0.0, 0.0] -sd_attributespvdDisplay.DataAxesGrid.XAxisUseCustomLabels = 1 -sd_attributespvdDisplay.DataAxesGrid.YAxisUseCustomLabels = 1 - -# current camera placement for renderView1 and layout -layout1 = pvs.GetLayout() -layout1.SetSize(1592, 1128) -renderView1.CameraPosition = [1548.945972263949, -1349.493616194682, 699.2699178747185] -renderView1.CameraFocalPoint = [ - -1.3686701146742275e-13, - 3.1755031232028544e-13, - 505.00000000000017, -] -renderView1.CameraViewUp = [ - -0.07221292769632315, - 0.06043215330151439, - 0.9955567527373153, -] -renderView1.CameraParallelScale = 534.07781536883 - -# get animation scene -animationScene1 = pvs.GetAnimationScene() -animationScene1.UpdateAnimationUsingDataTimeSteps() - -output_animation_path = r"C:\Users\strza\Desktop\PySDM\examples\PySDM_examples\Pyrcel\output_animation.avi" # Change the extension as needed -output_screenshot_path = ( +rHlookup_table = pvs.GetColorTransferFunction("RH") +volumelookup_table = pvs.GetColorTransferFunction("volume") + + +def configure_color_bar_and_display(display, lookup_table, kind): + """ + Configure color bar and display settings. + """ + display.Representation = "Surface" + display.SetScalarBarVisibility(renderView1, True) + color_bar = pvs.GetScalarBar(lookup_table, renderView1) + color_bar.LabelColor = [0.0, 0.0, 0.0] + color_bar.DrawScalarBarOutline = 1 + color_bar.ScalarBarOutlineColor = [0.0, 0.0, 0.0] + color_bar.TitleColor = [0.0, 0.0, 0.0] + + if kind == "prod": + display.Opacity = 0.4 + display.DisableLighting = 1 + display.Diffuse = 0.76 + lookup_table.RescaleTransferFunction(90.0, 101.0) + lookup_table.ApplyPreset("Black, Blue and White", True) + lookup_table.NanColor = [0.67, 1.0, 1.0] + else: + display.PointSize = 13.0 + display.RenderPointsAsSpheres = 1 + display.Interpolation = "PBR" + lookup_table.RescaleTransferFunction(1e-18, 1e-13) + lookup_table.ApplyPreset("Cold and Hot", True) + lookup_table.MapControlPointsToLogSpace() + lookup_table.UseLogScale = 1 + lookup_table.NumberOfTableValues = 16 + lookup_table.InvertTransferFunction() + + +def configure_data_axes_grid(display, kind): + """ + Configure data axes grid settings. + """ + display.DataAxesGrid.GridAxesVisibility = 1 + display.DataAxesGrid.XTitle = "" + display.DataAxesGrid.YTitle = "" + display.DataAxesGrid.XAxisUseCustomLabels = 1 + display.DataAxesGrid.YAxisUseCustomLabels = 1 + + if kind == "prod": + display.DataAxesGrid.ZTitle = "" + display.DataAxesGrid.GridColor = [0.0, 0.0, 0.0] + display.DataAxesGrid.ShowGrid = 1 + display.DataAxesGrid.LabelUniqueEdgesOnly = 0 + display.DataAxesGrid.ZAxisUseCustomLabels = 1 + else: + display.DataAxesGrid.ZTitle = "Z [m]" + display.DataAxesGrid.ZLabelColor = [0.0, 0.0, 0.0] + display.DataAxesGrid.ZTitleColor = [0.0, 0.0, 0.0] + + +def configure_view_appearance(render_view): + """ + Configure view appearance settings.""" + render_view.OrientationAxesLabelColor = [0.0, 0.0, 0.0] + render_view.OrientationAxesOutlineColor = [0.0, 0.0, 0.0] + render_view.OrientationAxesXVisibility = 0 + render_view.OrientationAxesYVisibility = 0 + render_view.OrientationAxesZColor = [0.0, 0.0, 0.0] + render_view.UseColorPaletteForBackground = 0 + render_view.Background = [1.0, 1.0, 1.0] + + +def set_camera_view(render_view): + """ + Set camera view settings. + """ + layout1 = pvs.GetLayout() + layout1.SetSize(1592, 1128) + render_view.CameraPosition = [ + 1548.945972263949, + -1349.493616194682, + 699.2699178747185, + ] + render_view.CameraFocalPoint = [ + -1.3686701146742275e-13, + 3.1755031232028544e-13, + 505.00000000000017, + ] + render_view.CameraViewUp = [ + -0.07221292769632315, + 0.06043215330151439, + 0.9955567527373153, + ] + render_view.CameraParallelScale = 534.07781536883 + + +def save_animation_and_screenshot(render_view, animation_path, screenshot_path): + """ + Save animation and screenshot.""" + animation_scene = pvs.GetAnimationScene() + animation_scene.UpdateAnimationUsingDataTimeSteps() + + pvs.SaveAnimation(animation_path, render_view, FrameRate=15) + pvs.SaveScreenshot(screenshot_path, render_view) + + +configure_color_bar_and_display(sd_productspvdDisplay, rHlookup_table, kind="prod") +configure_data_axes_grid(sd_productspvdDisplay, kind="prod") +configure_view_appearance(renderView1) +configure_color_bar_and_display( + sd_attributespvdDisplay, volumelookup_table, kind="attr" +) +configure_data_axes_grid(sd_attributespvdDisplay, kind="attr") +set_camera_view(renderView1) +OUTPUT_ANIMATION_PATH = r"C:\Users\strza\Desktop\PySDM\examples\PySDM_examples\Pyrcel\output_animation.avi" # pylint: disable=line-too-long +OUTPUT_SCREENSHOT_PATH = ( r"C:\Users\strza\Desktop\PySDM\examples\PySDM_examples\Pyrcel\last_frame.png" ) -pvs.SaveAnimation(output_animation_path, renderView1, FrameRate=15) -pvs.SaveScreenshot(output_screenshot_path, renderView1) +save_animation_and_screenshot( + renderView1, OUTPUT_ANIMATION_PATH, OUTPUT_SCREENSHOT_PATH +) From eb87f28bfca4abf43910ec81bc54f741df946966 Mon Sep 17 00:00:00 2001 From: olastrz Date: Wed, 8 Oct 2025 16:21:55 +0200 Subject: [PATCH 07/29] small fix --- examples/PySDM_examples/Pyrcel/paraview_simulation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/PySDM_examples/Pyrcel/paraview_simulation.py b/examples/PySDM_examples/Pyrcel/paraview_simulation.py index 8bd16d025..5eb3571fc 100644 --- a/examples/PySDM_examples/Pyrcel/paraview_simulation.py +++ b/examples/PySDM_examples/Pyrcel/paraview_simulation.py @@ -142,7 +142,8 @@ def set_camera_view(render_view): def save_animation_and_screenshot(render_view, animation_path, screenshot_path): """ - Save animation and screenshot.""" + Save animation and screenshot. + """ animation_scene = pvs.GetAnimationScene() animation_scene.UpdateAnimationUsingDataTimeSteps() From 1735e5b1260da3198a84763d80af32add6dca493 Mon Sep 17 00:00:00 2001 From: olastrz Date: Thu, 9 Oct 2025 12:12:14 +0200 Subject: [PATCH 08/29] new tuple and parsers --- .../Pyrcel/paraview_simulation.py | 78 ++++++++++++------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/examples/PySDM_examples/Pyrcel/paraview_simulation.py b/examples/PySDM_examples/Pyrcel/paraview_simulation.py index 5eb3571fc..bd3be700d 100644 --- a/examples/PySDM_examples/Pyrcel/paraview_simulation.py +++ b/examples/PySDM_examples/Pyrcel/paraview_simulation.py @@ -3,8 +3,11 @@ """ import argparse +from collections import namedtuple from paraview import simple as pvs # pylint: disable=import-error +pvs._DisableFirstRenderCameraReset() # pylint: disable=protected-access + def cli_using_argparse(argparse_parser): """ @@ -22,6 +25,16 @@ def cli_using_argparse(argparse_parser): default=r"C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes.pvd", # pylint: disable=line-too-long help="Path to sd_attributes.pvd", ) + argparse_parser.add_argument( + "--output-animation-path", + default=r"C:\Users\strza\Desktop\PySDM\examples\PySDM_examples\Pyrcel\output_animation.avi", # pylint: disable=line-too-long + help="Output path for the animation file.", + ) + argparse_parser.add_argument( + "--output-screenshot-path", + default=r"C:\Users\strza\Desktop\PySDM\examples\PySDM_examples\Pyrcel\last_frame.png", # pylint: disable=line-too-long + help="Output path for the screenshot file.", + ) parser = argparse.ArgumentParser( @@ -30,34 +43,41 @@ def cli_using_argparse(argparse_parser): cli_using_argparse(parser) args = parser.parse_args() -# TODO tuple -pvs._DisableFirstRenderCameraReset() # pylint: disable=protected-access -renderView1 = pvs.GetActiveViewOrCreate("RenderView") sd_productspvd = pvs.PVDReader( - registrationName="sd_products.pvd", - FileName=args.sd_products_pvd, -) -sd_productspvdDisplay = pvs.Show( - sd_productspvd, renderView1, "UnstructuredGridRepresentation" + registrationName="sd_products.pvd", FileName=args.sd_products_pvd ) sd_attributespvd = pvs.PVDReader( - registrationName="sd_attributes.pvd", - FileName=args.sd_attributes_pvd, -) -sd_attributespvdDisplay = pvs.Show( - sd_attributespvd, renderView1, "UnstructuredGridRepresentation" + registrationName="sd_attributes.pvd", FileName=args.sd_attributes_pvd ) -rHlookup_table = pvs.GetColorTransferFunction("RH") -volumelookup_table = pvs.GetColorTransferFunction("volume") - -def configure_color_bar_and_display(display, lookup_table, kind): +setup = { + "renderView1": pvs.GetActiveViewOrCreate("RenderView"), + "sd_productspvdDisplay": pvs.Show( + sd_productspvd, + pvs.GetActiveViewOrCreate("RenderView"), + "UnstructuredGridRepresentation", + ), + "sd_attributespvdDisplay": pvs.Show( + sd_attributespvd, + pvs.GetActiveViewOrCreate("RenderView"), + "UnstructuredGridRepresentation", + ), + "rHlookup_table": pvs.GetColorTransferFunction("RH"), + "volumelookup_table": pvs.GetColorTransferFunction("volume"), +} + +animation_setup = namedtuple("setup", setup.keys())(**setup) + + +def configure_color_bar_and_display( + display, lookup_table, kind, *, anim_setup=animation_setup +): """ Configure color bar and display settings. """ display.Representation = "Surface" - display.SetScalarBarVisibility(renderView1, True) - color_bar = pvs.GetScalarBar(lookup_table, renderView1) + display.SetScalarBarVisibility(anim_setup.renderView1, True) + color_bar = pvs.GetScalarBar(lookup_table, anim_setup.renderView1) color_bar.LabelColor = [0.0, 0.0, 0.0] color_bar.DrawScalarBarOutline = 1 color_bar.ScalarBarOutlineColor = [0.0, 0.0, 0.0] @@ -151,18 +171,18 @@ def save_animation_and_screenshot(render_view, animation_path, screenshot_path): pvs.SaveScreenshot(screenshot_path, render_view) -configure_color_bar_and_display(sd_productspvdDisplay, rHlookup_table, kind="prod") -configure_data_axes_grid(sd_productspvdDisplay, kind="prod") -configure_view_appearance(renderView1) configure_color_bar_and_display( - sd_attributespvdDisplay, volumelookup_table, kind="attr" + animation_setup.sd_productspvdDisplay, animation_setup.rHlookup_table, kind="prod" ) -configure_data_axes_grid(sd_attributespvdDisplay, kind="attr") -set_camera_view(renderView1) -OUTPUT_ANIMATION_PATH = r"C:\Users\strza\Desktop\PySDM\examples\PySDM_examples\Pyrcel\output_animation.avi" # pylint: disable=line-too-long -OUTPUT_SCREENSHOT_PATH = ( - r"C:\Users\strza\Desktop\PySDM\examples\PySDM_examples\Pyrcel\last_frame.png" +configure_data_axes_grid(animation_setup.sd_productspvdDisplay, kind="prod") +configure_view_appearance(animation_setup.renderView1) +configure_color_bar_and_display( + animation_setup.sd_attributespvdDisplay, + animation_setup.volumelookup_table, + kind="attr", ) +configure_data_axes_grid(animation_setup.sd_attributespvdDisplay, kind="attr") +set_camera_view(animation_setup.renderView1) save_animation_and_screenshot( - renderView1, OUTPUT_ANIMATION_PATH, OUTPUT_SCREENSHOT_PATH + animation_setup.renderView1, args.output_animation_path, args.output_screenshot_path ) From 8daa14d5e70e3125ece428a74c7328520b20f936 Mon Sep 17 00:00:00 2001 From: olastrz Date: Fri, 7 Nov 2025 22:23:25 +0100 Subject: [PATCH 09/29] Final fix to simulation --- examples/PySDM_examples/Pyrcel/paraview.ipynb | 59 ++++++++++++++++--- .../Pyrcel/paraview_simulation.py | 4 -- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/examples/PySDM_examples/Pyrcel/paraview.ipynb b/examples/PySDM_examples/Pyrcel/paraview.ipynb index 94e19d933..5553582d6 100644 --- a/examples/PySDM_examples/Pyrcel/paraview.ipynb +++ b/examples/PySDM_examples/Pyrcel/paraview.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 10, + "execution_count": 1, "id": "6dcbcc6d", "metadata": {}, "outputs": [ @@ -16,6 +16,9 @@ ], "source": [ "import numpy as np\n", + "import subprocess\n", + "import platform\n", + "import pathlib\n", "from PySDM import Formulae\n", "from PySDM.physics import si\n", "from PySDM.initialisation.spectra import Lognormal\n", @@ -42,7 +45,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 2, "id": "cd6288b5", "metadata": {}, "outputs": [], @@ -85,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 3, "id": "3ff50a25", "metadata": {}, "outputs": [], @@ -95,7 +98,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 4, "id": "15d59657", "metadata": {}, "outputs": [], @@ -109,11 +112,53 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "4a6ea0e6", "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Script paraview_simulation.py executed successfully.\n", + "STDOUT: VisRTX 0.1.6, using devices:\n", + " 0: NVIDIA GeForce RTX 4050 Laptop GPU (Total: 6.4 GB, Available: 5.3 GB)\n", + "\n" + ] + } + ], + "source": [ + "\n", + "\n", + "product = pathlib.Path(\"./output/sd_products.pvd\").absolute()\n", + "attributes = pathlib.Path(\"./output/sd_attributes.pvd\").absolute()\n", + "\n", + "paraview_script = pathlib.Path(\"./paraview_simulation.py\").absolute()\n", + "\n", + "args = [\n", + " \"pvpython\",\n", + " \"--force-offscreen-rendering\",\n", + " str(paraview_script),\n", + " \"--sd-products-pvd\", str(product),\n", + " \"--sd-attributes-pvd\", str(attributes),\n", + " \"--output-animation-path\", str(pathlib.Path(\"./output/animation.avi\").absolute()),\n", + " \"--output-screenshot-path\", str(pathlib.Path(\"./output/last_frame.png\").absolute())\n", + "]\n", + "try:\n", + " result = subprocess.run(\n", + " args,\n", + " check=platform.system() != \"Windows\",\n", + " capture_output=True,\n", + " text=True,\n", + " )\n", + " print(\"Script paraview_simulation.py executed successfully.\")\n", + " if result.stdout:\n", + " print(\"STDOUT:\", result.stdout)\n", + "except subprocess.CalledProcessError as e:\n", + " print(\"Error during script execution:\")\n", + " print(\"STDERR:\", e.stderr)\n", + " print(\"STDOUT:\", e.stdout)" + ] } ], "metadata": { diff --git a/examples/PySDM_examples/Pyrcel/paraview_simulation.py b/examples/PySDM_examples/Pyrcel/paraview_simulation.py index bd3be700d..625348651 100644 --- a/examples/PySDM_examples/Pyrcel/paraview_simulation.py +++ b/examples/PySDM_examples/Pyrcel/paraview_simulation.py @@ -16,23 +16,19 @@ def cli_using_argparse(argparse_parser): argparse_parser.add_argument( "--sd-products-pvd", dest="sd_products_pvd", - default=r"C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_products.pvd", # pylint: disable=line-too-long help="Path to sd_products.pvd", ) argparse_parser.add_argument( "--sd-attributes-pvd", dest="sd_attributes_pvd", - default=r"C:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\output\\sd_attributes.pvd", # pylint: disable=line-too-long help="Path to sd_attributes.pvd", ) argparse_parser.add_argument( "--output-animation-path", - default=r"C:\Users\strza\Desktop\PySDM\examples\PySDM_examples\Pyrcel\output_animation.avi", # pylint: disable=line-too-long help="Output path for the animation file.", ) argparse_parser.add_argument( "--output-screenshot-path", - default=r"C:\Users\strza\Desktop\PySDM\examples\PySDM_examples\Pyrcel\last_frame.png", # pylint: disable=line-too-long help="Output path for the screenshot file.", ) From 7f12278075703692e70f04af9f2a242b8add757b Mon Sep 17 00:00:00 2001 From: olastrz Date: Thu, 13 Nov 2025 14:19:47 +0100 Subject: [PATCH 10/29] bump python version for pylint CI job --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 136d96f57..439afd6c2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -62,7 +62,7 @@ jobs: strategy: matrix: platform: [ubuntu-24.04] - python-version: ["3.9"] + python-version: ["3.12"] runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v4.1.6 From 6d01174d5a3e4c9aac329f02287001f8850b5eba Mon Sep 17 00:00:00 2001 From: olastrz Date: Thu, 13 Nov 2025 14:28:48 +0100 Subject: [PATCH 11/29] refrain from using walrus op in parcel exporter --- PySDM/exporters/parcel_vtk_exporter.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/PySDM/exporters/parcel_vtk_exporter.py b/PySDM/exporters/parcel_vtk_exporter.py index 1b58732da..fa034b05f 100644 --- a/PySDM/exporters/parcel_vtk_exporter.py +++ b/PySDM/exporters/parcel_vtk_exporter.py @@ -73,10 +73,14 @@ def export_products( for level in range(self.n_levels): hd = self.half_diagonal[level] _z = self.output["products"]["z"][level] - x[i := level * 4], y[i], z[i] = -hd, -hd, _z - x[i := i + 1], y[i], z[i] = -hd, hd, _z - x[i := i + 1], y[i], z[i] = hd, hd, _z - x[i := i + 1], y[i], z[i] = hd, -hd, _z + i = level * 4 + x[i], y[i], z[i] = -hd, -hd, _z + i += 1 + x[i], y[i], z[i] = -hd, hd, _z + i += 1 + x[i], y[i], z[i] = hd, hd, _z + i += 1 + x[i], y[i], z[i] = hd, -hd, _z conn += [*range(4 * (level + 1), 4 * (level + 2))] * 2 conn = np.asarray(conn[:-4]) offset = np.asarray(range(8, 8 * self.n_levels, 8)) From ce177d5747571f0df35bda7fdc4dc8ea32494442 Mon Sep 17 00:00:00 2001 From: olastrz Date: Thu, 13 Nov 2025 14:31:36 +0100 Subject: [PATCH 12/29] add missing __init__ file --- .../PySDM_examples/Strzabala_engineering_thesis_2025/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/PySDM_examples/Strzabala_engineering_thesis_2025/__init__.py diff --git a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/__init__.py b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/__init__.py new file mode 100644 index 000000000..e69de29bb From a239e4a824b31303f78f0180c5ff677f5e60e9e2 Mon Sep 17 00:00:00 2001 From: Sylwester Arabas Date: Sun, 16 Nov 2025 00:08:42 +0100 Subject: [PATCH 13/29] revert Python version change --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 085699b8a..52e4d9ee5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -62,7 +62,7 @@ jobs: strategy: matrix: platform: [ubuntu-24.04] - python-version: ["3.12"] + python-version: ["3.9"] runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v4.1.6 From 523b200ad79730aa385eed9eca238eb81d33494a Mon Sep 17 00:00:00 2001 From: olastrz Date: Thu, 20 Nov 2025 00:51:38 +0100 Subject: [PATCH 14/29] New updates from pylint suggestions --- .../calc2.py | 241 +++++++++--------- .../no_glyphs.py | 197 +++++++------- 2 files changed, 234 insertions(+), 204 deletions(-) diff --git a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py index ade9b36f8..69f992413 100644 --- a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py +++ b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py @@ -1,3 +1,5 @@ +"""Module for processing PVD files and rendering visualizations using ParaView.""" + #!/usr/bin/env pvpython import argparse from collections import namedtuple @@ -5,10 +7,11 @@ from paraview import simple as pvs # pylint: disable=import-error -pvs._DisableFirstRenderCameraReset() +pvs._DisableFirstRenderCameraReset() # pylint: disable=protected-access def cli_using_argparse(argp): + """Set up command line argument parsing.""" argp.add_argument("product_path", help="path to pvd products file") argp.add_argument("attributes_path", help=" path to pvd attributes file") argp.add_argument("output_path", help="path where to write output files") @@ -110,81 +113,91 @@ def cli_using_argparse(argp): setup.renderView1.Update() -def create_new_calculator( - calcinput, - representation, - function, - color_by1, - color_by2, - color_by3, - scalar_coloring=False, - hide=False, - *, - y, - registrationame, -): - calculator = pvs.Calculator(registrationName=registrationame, Input=calcinput) - display = pvs.Show(calculator, y.renderView1, representation) +def create_new_calculator(params): + """Create a new calculator in ParaView.""" + calcinput = params["calcinput"] + representation = params["representation"] + function = params["function"] + color_by1 = params["color_by1"] + color_by2 = params["color_by2"] + color_by3 = params["color_by3"] + scalar_coloring = params.get("scalar_coloring", False) + hide = params.get("hide", False) + setup_context = params["setup_context"] + registration_name = params["registration_name"] + + calculator = pvs.Calculator(registrationName=registration_name, Input=calcinput) + display = pvs.Show(calculator, setup_context.renderView1, representation) calculator.Function = function - y.renderView1.Update() - if scalar_coloring is True: + setup_context.renderView1.Update() + if scalar_coloring: pvs.ColorBy(display, (color_by1, color_by2, color_by3)) - if hide is True: - pvs.Hide(calculator, y.renderView1) - return y.renderView1.Update() + if hide: + pvs.Hide(calculator, setup_context.renderView1) + return setup_context.renderView1.Update() def scalar_bar(name, *, y, erLUT): - calculator1Display = pvs.Show( + """Display a scalar bar for the given name.""" + calculator1_display = pvs.Show( calculator1, y.renderView1, "UnstructuredGridRepresentation" ) - calculator1Display.SetScalarBarVisibility(y.renderView1, True) - scalarBar = pvs.GetScalarBar(erLUT.effectiveradiusLUT, y.renderView1) - scalarBar.ComponentTitle = "" - scalarBar.Title = name - scalarBar.TitleFontSize = 25 - scalarBar.LabelFontSize = 25 - scalarBar.LabelColor = setup.color - scalarBar.TitleColor = setup.color - pvs.Hide(scalarBar) + calculator1_display.SetScalarBarVisibility(y.renderView1, True) + scalar_bar_instance = pvs.GetScalarBar(erLUT.effectiveradiusLUT, y.renderView1) + scalar_bar_instance.ComponentTitle = "" + scalar_bar_instance.Title = name + scalar_bar_instance.TitleFontSize = 25 + scalar_bar_instance.LabelFontSize = 25 + scalar_bar_instance.LabelColor = setup.color + scalar_bar_instance.TitleColor = setup.color + pvs.Hide(scalar_bar_instance) y.renderView1.Update() -def create_glyph( - registration_name, put, scale_array1, scale_array2, color_by=False, *, y -): +def create_glyph(params): + """Create a glyph representation in ParaView.""" + registration_name = params["registration_name"] + put = params["put"] + scale_array1 = params["scale_array1"] + scale_array2 = params["scale_array2"] + color_by = params.get("color_by", False) + glyph = pvs.Glyph(registrationName=registration_name, Input=put, GlyphType="Arrow") - glyphDisplay = pvs.Show(glyph, y.renderView1, "GeometryRepresentation") - glyphDisplay.Representation = "Surface" + glyph_display = pvs.Show(glyph, setup.renderView1, "GeometryRepresentation") + glyph_display.Representation = "Surface" glyph.ScaleArray = [scale_array1, scale_array2] glyph.ScaleFactor = 100 - glyphDisplay.SetScalarBarVisibility(y.renderView1, True) - multiplicityLUT = pvs.GetColorTransferFunction("multiplicity") - multiplicityLUTColorBar = pvs.GetScalarBar(multiplicityLUT, y.renderView1) - multiplicityLUTColorBar.Position = [0.8, 0.5] - multiplicityLUTColorBar.TitleFontSize = 25 - multiplicityLUTColorBar.LabelFontSize = 25 - multiplicityLUTColorBar.LabelColor = setup.color - multiplicityLUTColorBar.TitleColor = setup.color - if color_by is True: - glyphDisplay.ColorArrayName = ["POINTS", ""] - pvs.ColorBy(glyphDisplay, None) - y.renderView1.Update() + glyph_display.SetScalarBarVisibility(setup.renderView1, True) + + multiplicity_lut = pvs.GetColorTransferFunction("multiplicity") + multiplicity_lut_color_bar = pvs.GetScalarBar(multiplicity_lut, setup.renderView1) + multiplicity_lut_color_bar.Position = [0.5, 0.9] + multiplicity_lut_color_bar.TitleFontSize = 25 + multiplicity_lut_color_bar.LabelFontSize = 25 + multiplicity_lut_color_bar.LabelColor = setup.color + multiplicity_lut_color_bar.TitleColor = setup.color + + if color_by: + glyph_display.ColorArrayName = ["POINTS", ""] + pvs.ColorBy(glyph_display, None) + + setup.renderView1.Update() def apply_presets_logscale_opacity_and_update(*, y, attdisplay, erLUT, proddisplay): - multiplicityLUT = pvs.GetColorTransferFunction("multiplicity") - multiplicityLUT.RescaleTransferFunction(19951.0, 50461190157.0) - calculator1Display = pvs.Show( + """Apply presets, log scale, opacity settings, and update the view.""" + multiplicity_lut = pvs.GetColorTransferFunction("multiplicity") + multiplicity_lut.RescaleTransferFunction(19951.0, 50461190157.0) + calculator1_display = pvs.Show( calculator1, y.renderView1, "UnstructuredGridRepresentation" ) - multiplicityLUT.ApplyPreset(args.multiplicity_preset, True) + multiplicity_lut.ApplyPreset(args.multiplicity_preset, True) if args.multiplicity_logscale: - multiplicityLUT.MapControlPointsToLogSpace() - multiplicityLUT.UseLogScale = 1 + multiplicity_lut.MapControlPointsToLogSpace() + multiplicity_lut.UseLogScale = 1 else: - multiplicityLUT.MapControlPointsToLinearSpace() - multiplicityLUT.UseLogScale = 0 + multiplicity_lut.MapControlPointsToLinearSpace() + multiplicity_lut.UseLogScale = 0 erLUT.effectiveradiusLUT.ApplyPreset(args.effectiveradius_preset, True) if args.effectiveradius_logscale: @@ -195,15 +208,15 @@ def apply_presets_logscale_opacity_and_update(*, y, attdisplay, erLUT, proddispl erLUT.effectiveradiusLUT.UseLogScale = 0 erLUT.effectiveradiusLUT.NanColor = args.effectiveradius_nan_color - # proddisplay.sd_productspvdDisplay.SetRepresentationType("Surface With Edges") proddisplay.sd_productspvdDisplay.Opacity = args.sd_products_opacity proddisplay.sd_productspvdDisplay.SetScalarBarVisibility(y.renderView1, False) - calculator1Display.Opacity = args.calculator1_opacity + calculator1_display.Opacity = args.calculator1_opacity attdisplay.sd_attributespvdDisplay.Opacity = args.sd_attributes_opacity y.renderView1.Update() def get_layout(*, y): + """Set the layout for the render view.""" pvs.SetViewProperties( Background=setup.inverted_color, UseColorPaletteForBackground=0 ) @@ -215,12 +228,9 @@ def get_layout(*, y): def set_current_camera_placement(*, y): + """Set the camera placement for the render view.""" y.renderView1.InteractionMode = "2D" - y.renderView1.CameraPosition = [ - 836, - 677, - -4098, - ] + y.renderView1.CameraPosition = [836, 677, -4098] y.renderView1.CameraFocalPoint = [636, 1030, 0.0] y.renderView1.CameraViewUp = [1.0, 0.0, 0.0] y.renderView1.CameraParallelScale = 1560 @@ -228,34 +238,35 @@ def set_current_camera_placement(*, y): def axes_settings(*, view): - # setup.renderView1.Background = [1,0.5,0.2] + """Configure axes settings for the render view.""" view.CenterAxesVisibility = True view.OrientationAxesVisibility = False - axesGrid = view.AxesGrid - axesGrid.Visibility = True - axesGrid.XTitle = "Z [m]" - axesGrid.YTitle = "X [m]" - - axesGrid.XAxisUseCustomLabels = True - axesGrid.XAxisLabels = [300, 600, 900, 1200] - axesGrid.YAxisUseCustomLabels = True - axesGrid.YAxisLabels = [300, 600, 900, 1200] - - axesGrid.XTitleFontSize = 30 - axesGrid.XLabelFontSize = 30 - axesGrid.YTitleFontSize = 30 - axesGrid.YLabelFontSize = 30 - - axesGrid.XTitleColor = setup.color - axesGrid.XLabelColor = setup.color - axesGrid.YTitleColor = setup.color - axesGrid.YLabelColor = setup.color - axesGrid.GridColor = [0.1, 0.1, 0.1] + axes_grid = view.AxesGrid + axes_grid.Visibility = True + axes_grid.XTitle = "Z [m]" + axes_grid.YTitle = "X [m]" + + axes_grid.XAxisUseCustomLabels = True + axes_grid.XAxisLabels = [300, 600, 900, 1200] + axes_grid.YAxisUseCustomLabels = True + axes_grid.YAxisLabels = [300, 600, 900, 1200] + + axes_grid.XTitleFontSize = 30 + axes_grid.XLabelFontSize = 30 + axes_grid.YTitleFontSize = 30 + axes_grid.YLabelFontSize = 30 + + axes_grid.XTitleColor = setup.color + axes_grid.XLabelColor = setup.color + axes_grid.YTitleColor = setup.color + axes_grid.YLabelColor = setup.color + axes_grid.GridColor = [0.1, 0.1, 0.1] view.CenterAxesVisibility = False view.Update() def time_annotation(*, y): + """Add a time annotation to the render view.""" time = pvs.AnnotateTimeFilter( guiName="AnnotateTimeFilter1", Scale=1 / 60, Format="Time:{time:g}min" ) @@ -269,16 +280,18 @@ def time_annotation(*, y): def text(text_in, position_y, *, view): + """Display text in the render view at a specified position.""" sentence = pvs.Text() sentence.Text = text_in - textDisplay = pvs.Show(sentence, view) - textDisplay.Color = setup.color - textDisplay.WindowLocation = "Any Location" - textDisplay.FontSize = 28 - textDisplay.Position = [0.17, position_y] + text_display = pvs.Show(sentence, view) + text_display.Color = setup.color + text_display.WindowLocation = "Any Location" + text_display.FontSize = 28 + text_display.Position = [0.17, position_y] def last_anim_frame(animation_frame_name): + """Export the last animation frame to a file.""" time_steps = sd_productspvd.TimestepValues last_time = time_steps[90] setup.renderView1.ViewTime = last_time @@ -294,38 +307,34 @@ def last_anim_frame(animation_frame_name): calculator1 = create_new_calculator( - sd_attributespvd, - "UnstructuredGridRepresentation", - '"relative fall velocity"*(-iHat)', - "None", - "None", - "None", - y=setup, - registrationame="Calculator1", + { + "calcinput": sd_attributespvd, + "representation": "UnstructuredGridRepresentation", + "function": '"relative fall velocity"*(-iHat)', + "color_by1": "None", + "color_by2": "None", + "color_by3": "None", + "scalar_coloring": False, + "hide": False, + "setup_context": setup, + "registration_name": "Calculator1", + } ) -# scalar_bar("effective radius [um]", y=setup, erLUT=setup) -glyph1 = create_glyph( - "Glyph1", calculator1, "POINTS", "relative fall velocity", y=setup + +create_glyph( + { + "registration_name": "Glyph1", + "put": calculator1, + "scale_array1": "POINTS", + "scale_array2": "relative fall velocity", + "color_by": False, + "setup_context": setup, + } ) -pvs.Hide(glyph1) -"""calculator2 = create_new_calculator( - sd_productspvd, - "StructuredGridRepresentation", - "cx*jHat+cy*iHat", - "CELLS", - "Result", - "Magnitude", - True, - True, - y=setup, - registrationame="Calculator2", -)""" -# pvs.Hide(calculator2) + apply_presets_logscale_opacity_and_update( y=setup, attdisplay=setup, erLUT=setup, proddisplay=setup ) -# glyph2 = create_glyph("Glyph2", calculator2, "CELLS", "Result", True, y=setup) -# pvs.Hide(glyph2) get_layout(y=setup) set_current_camera_placement(y=setup) axes_settings(view=setup.renderView1) diff --git a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py index 803819ecb..73e2ff84c 100644 --- a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py +++ b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py @@ -1,21 +1,34 @@ #!/usr/bin/env pvpython +"""Paraview rendering script. + +This module prepares Paraview scene, calculators, glyphs and exports animation/images. +Lint fixes: module docstring, protected-access disabled inline, reduced function args, +and short docstrings added to public functions. +""" import argparse from collections import namedtuple import pathlib from paraview import simple as pvs # pylint: disable=import-error -pvs._DisableFirstRenderCameraReset() +pvs._DisableFirstRenderCameraReset() # pylint: disable=protected-access def cli_using_argparse(argp): + """Add and document command-line arguments used by this pvpython script. + + Parameters + ---------- + argp : argparse.ArgumentParser + ArgumentParser instance to which this function will add arguments. + """ argp.add_argument("product_path", help="path to pvd products file") argp.add_argument("attributes_path", help=" path to pvd attributes file") argp.add_argument("output_path", help="path where to write output files") argp.add_argument( "--mode", choices=["light", "dark"], - default="dark", + default="light", help="Choose 'light' or 'dark' mode.", ) argp.add_argument( @@ -114,75 +127,81 @@ def create_new_calculator( calcinput, representation, function, - color_by1, - color_by2, - color_by3, + color_by, + *, scalar_coloring=False, hide=False, - *, y, - registrationame, + registration_name, ): - calculator = pvs.Calculator(registrationName=registrationame, Input=calcinput) + """Create and show a Calculator filter; return the calculator object. + + color_by should be a tuple (arrayName, association, component) or None. + """ + calculator = pvs.Calculator(registrationName=registration_name, Input=calcinput) display = pvs.Show(calculator, y.renderView1, representation) calculator.Function = function y.renderView1.Update() - if scalar_coloring is True: - pvs.ColorBy(display, (color_by1, color_by2, color_by3)) - if hide is True: + if scalar_coloring and color_by: + pvs.ColorBy(display, tuple(color_by)) + if hide: pvs.Hide(calculator, y.renderView1) - return y.renderView1.Update() + return calculator -def scalar_bar(name, *, y, erLUT): - calculator1Display = pvs.Show( - calculator1, y.renderView1, "UnstructuredGridRepresentation" +def scalar_bar(name, *, y, erLUT, calculator): + """Ensure scalar bar for given calculator is visible and styled.""" + calculator_display = pvs.Show( + calculator, y.renderView1, "UnstructuredGridRepresentation" ) - calculator1Display.SetScalarBarVisibility(y.renderView1, True) - scalarBar = pvs.GetScalarBar(erLUT.effectiveradiusLUT, y.renderView1) - scalarBar.ComponentTitle = "" - scalarBar.Title = name - scalarBar.TitleFontSize = 25 - scalarBar.LabelFontSize = 25 - scalarBar.LabelColor = setup.color - scalarBar.TitleColor = setup.color + calculator_display.SetScalarBarVisibility(y.renderView1, True) + scalar_bar_obj = pvs.GetScalarBar(erLUT.effectiveradiusLUT, y.renderView1) + scalar_bar_obj.ComponentTitle = "" + scalar_bar_obj.Title = name + scalar_bar_obj.TitleFontSize = 25 + scalar_bar_obj.LabelFontSize = 25 + scalar_bar_obj.LabelColor = setup.color + scalar_bar_obj.TitleColor = setup.color y.renderView1.Update() def create_glyph( registration_name, put, scale_array1, scale_array2, color_by=False, *, y ): + """Create a glyph and return it.""" glyph = pvs.Glyph(registrationName=registration_name, Input=put, GlyphType="Arrow") - glyphDisplay = pvs.Show(glyph, y.renderView1, "GeometryRepresentation") - glyphDisplay.Representation = "Surface" + glyph_display = pvs.Show(glyph, y.renderView1, "GeometryRepresentation") + glyph_display.Representation = "Surface" glyph.ScaleArray = [scale_array1, scale_array2] glyph.ScaleFactor = 100 - glyphDisplay.SetScalarBarVisibility(y.renderView1, True) - multiplicityLUT = pvs.GetColorTransferFunction("multiplicity") - multiplicityLUTColorBar = pvs.GetScalarBar(multiplicityLUT, y.renderView1) - multiplicityLUTColorBar.TitleFontSize = 25 - multiplicityLUTColorBar.LabelFontSize = 25 - multiplicityLUTColorBar.LabelColor = setup.color - multiplicityLUTColorBar.TitleColor = setup.color - if color_by is True: - glyphDisplay.ColorArrayName = ["POINTS", ""] - pvs.ColorBy(glyphDisplay, None) + glyph_display.SetScalarBarVisibility(y.renderView1, True) + multiplicity_lut = pvs.GetColorTransferFunction("multiplicity") + multiplicity_lut_color_bar = pvs.GetScalarBar(multiplicity_lut, y.renderView1) + multiplicity_lut_color_bar.TitleFontSize = 25 + multiplicity_lut_color_bar.LabelFontSize = 25 + multiplicity_lut_color_bar.LabelColor = setup.color + multiplicity_lut_color_bar.TitleColor = setup.color + if color_by: + glyph_display.ColorArrayName = ["POINTS", ""] + pvs.ColorBy(glyph_display, None) y.renderView1.Update() + return glyph def apply_presets_logscale_opacity_and_update(*, y, attdisplay, erLUT, proddisplay): - multiplicityLUT = pvs.GetColorTransferFunction("multiplicity") - multiplicityLUT.RescaleTransferFunction(19951.0, 50461190157.0) - calculator1Display = pvs.Show( - calculator1, y.renderView1, "UnstructuredGridRepresentation" + """Apply LUT presets / logscale and set object opacities.""" + multiplicity_lut = pvs.GetColorTransferFunction("multiplicity") + multiplicity_lut.RescaleTransferFunction(19951.0, 50461190157.0) + calculator_1_display = pvs.Show( + calculator_1, y.renderView1, "UnstructuredGridRepresentation" ) - multiplicityLUT.ApplyPreset(args.multiplicity_preset, True) + multiplicity_lut.ApplyPreset(args.multiplicity_preset, True) if args.multiplicity_logscale: - multiplicityLUT.MapControlPointsToLogSpace() - multiplicityLUT.UseLogScale = 1 + multiplicity_lut.MapControlPointsToLogSpace() + multiplicity_lut.UseLogScale = 1 else: - multiplicityLUT.MapControlPointsToLinearSpace() - multiplicityLUT.UseLogScale = 0 + multiplicity_lut.MapControlPointsToLinearSpace() + multiplicity_lut.UseLogScale = 0 erLUT.effectiveradiusLUT.ApplyPreset(args.effectiveradius_preset, True) if args.effectiveradius_logscale: @@ -196,13 +215,14 @@ def apply_presets_logscale_opacity_and_update(*, y, attdisplay, erLUT, proddispl proddisplay.sd_productspvdDisplay.SetRepresentationType("Surface With Edges") proddisplay.sd_productspvdDisplay.Opacity = args.sd_products_opacity - calculator1Display.Opacity = args.calculator1_opacity + calculator_1_display.Opacity = args.calculator1_opacity attdisplay.sd_attributespvdDisplay.Opacity = args.sd_attributes_opacity y.renderView1.Update() def get_layout(*, y): + """Configure layout size for animation rendering.""" pvs.SetViewProperties( Background=setup.inverted_color, UseColorPaletteForBackground=0 ) @@ -214,6 +234,7 @@ def get_layout(*, y): def set_current_camera_placement(*, y): + """Set camera placement for the scene.""" y.renderView1.InteractionMode = "2D" y.renderView1.CameraPosition = [ 836, @@ -227,34 +248,36 @@ def set_current_camera_placement(*, y): def axes_settings(*, view): + """Configure axes grid, labels and styling on given view.""" # setup.renderView1.Background = [1,0.5,0.2] view.CenterAxesVisibility = True view.OrientationAxesVisibility = False - axesGrid = view.AxesGrid - axesGrid.Visibility = True - axesGrid.XTitle = "Z [m]" - axesGrid.YTitle = "X [m]" - - axesGrid.XAxisUseCustomLabels = True - axesGrid.XAxisLabels = [300, 600, 900, 1200] - axesGrid.YAxisUseCustomLabels = True - axesGrid.YAxisLabels = [300, 600, 900, 1200] - - axesGrid.XTitleFontSize = 30 - axesGrid.XLabelFontSize = 30 - axesGrid.YTitleFontSize = 30 - axesGrid.YLabelFontSize = 30 - - axesGrid.XTitleColor = setup.color - axesGrid.XLabelColor = setup.color - axesGrid.YTitleColor = setup.color - axesGrid.YLabelColor = setup.color - axesGrid.GridColor = [0.1, 0.1, 0.1] + axes_grid = view.AxesGrid + axes_grid.Visibility = True + axes_grid.XTitle = "Z [m]" + axes_grid.YTitle = "X [m]" + + axes_grid.XAxisUseCustomLabels = True + axes_grid.XAxisLabels = [300, 600, 900, 1200] + axes_grid.YAxisUseCustomLabels = True + axes_grid.YAxisLabels = [300, 600, 900, 1200] + + axes_grid.XTitleFontSize = 30 + axes_grid.XLabelFontSize = 30 + axes_grid.YTitleFontSize = 30 + axes_grid.YLabelFontSize = 30 + + axes_grid.XTitleColor = setup.color + axes_grid.XLabelColor = setup.color + axes_grid.YTitleColor = setup.color + axes_grid.YLabelColor = setup.color + axes_grid.GridColor = [0.1, 0.1, 0.1] view.CenterAxesVisibility = False view.Update() def time_annotation(*, y): + """Add time annotation to the view.""" time = pvs.AnnotateTimeFilter( guiName="AnnotateTimeFilter1", Scale=1 / 60, Format="Time:{time:g}min" ) @@ -268,16 +291,18 @@ def time_annotation(*, y): def text(text_in, position_y, *, view): + """Place a small text label on view (no return).""" sentence = pvs.Text() sentence.Text = text_in - textDisplay = pvs.Show(sentence, view) - textDisplay.Color = setup.color - textDisplay.WindowLocation = "Any Location" - textDisplay.FontSize = 28 - textDisplay.Position = [0.17, position_y] + text_display = pvs.Show(sentence, view) + text_display.Color = setup.color + text_display.WindowLocation = "Any Location" + text_display.FontSize = 28 + text_display.Position = [0.17, position_y] def last_anim_frame(animation_frame_name): + """Export last animation frame to a file in output path.""" time_steps = sd_productspvd.TimestepValues last_time = time_steps[90] setup.renderView1.ViewTime = last_time @@ -292,38 +317,34 @@ def last_anim_frame(animation_frame_name): pvs.RenderAllViews() -calculator1 = create_new_calculator( +calculator_1 = create_new_calculator( sd_attributespvd, "UnstructuredGridRepresentation", '"relative fall velocity"*(-iHat)', - "None", - "None", - "None", + ("None", "None", "None"), y=setup, - registrationame="Calculator1", + registration_name="Calculator1", ) -scalar_bar("effective radius [um]", y=setup, erLUT=setup) -glyph1 = create_glyph( - "Glyph1", calculator1, "POINTS", "relative fall velocity", y=setup +scalar_bar("effective radius [um]", y=setup, erLUT=setup, calculator=calculator_1) +glyph_1 = create_glyph( + "Glyph1", calculator_1, "POINTS", "relative fall velocity", y=setup ) -pvs.Hide(glyph1) -calculator2 = create_new_calculator( +pvs.Hide(glyph_1) +calculator_2 = create_new_calculator( sd_productspvd, "StructuredGridRepresentation", "cx*jHat+cy*iHat", - "CELLS", - "Result", - "Magnitude", - True, - True, + ("CELLS", "Result", "Magnitude"), + scalar_coloring=True, + hide=True, y=setup, - registrationame="Calculator2", + registration_name="Calculator2", ) apply_presets_logscale_opacity_and_update( y=setup, attdisplay=setup, erLUT=setup, proddisplay=setup ) -glyph2 = create_glyph("Glyph2", calculator2, "CELLS", "Result", True, y=setup) -pvs.Hide(glyph2) +glyph_2 = create_glyph("Glyph2", calculator_2, "CELLS", "Result", True, y=setup) +pvs.Hide(glyph_2) get_layout(y=setup) set_current_camera_placement(y=setup) axes_settings(view=setup.renderView1) From 5172c4709b778b0cc93cfe9134a4314d7457f560 Mon Sep 17 00:00:00 2001 From: olastrz Date: Thu, 20 Nov 2025 09:09:41 +0100 Subject: [PATCH 15/29] small pylint fix --- examples/PySDM_examples/Pyrcel/paraview.ipynb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/PySDM_examples/Pyrcel/paraview.ipynb b/examples/PySDM_examples/Pyrcel/paraview.ipynb index 5553582d6..e229b6d4f 100644 --- a/examples/PySDM_examples/Pyrcel/paraview.ipynb +++ b/examples/PySDM_examples/Pyrcel/paraview.ipynb @@ -40,12 +40,12 @@ "print(exporters_path)\n", "sys.path.append(exporters_path)\n", "\n", - "from parcel_vtk_exporter import VTKExporterPyrcel" + "from parcel_vtk_exporter import VTKExporterPyrcel #pylint: disable=import-error" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "cd6288b5", "metadata": {}, "outputs": [], @@ -88,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "3ff50a25", "metadata": {}, "outputs": [], @@ -98,7 +98,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "15d59657", "metadata": {}, "outputs": [], @@ -112,7 +112,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "4a6ea0e6", "metadata": {}, "outputs": [ From c2879d619859c72095342eeaa5791133eccf3a7a Mon Sep 17 00:00:00 2001 From: olastrz Date: Thu, 20 Nov 2025 14:04:06 +0100 Subject: [PATCH 16/29] small fix --- examples/PySDM_examples/Pyrcel/paraview_simulation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/PySDM_examples/Pyrcel/paraview_simulation.py b/examples/PySDM_examples/Pyrcel/paraview_simulation.py index 625348651..9f5c381a8 100644 --- a/examples/PySDM_examples/Pyrcel/paraview_simulation.py +++ b/examples/PySDM_examples/Pyrcel/paraview_simulation.py @@ -1,3 +1,4 @@ +#!/usr/bin/env pvpython """ ParaView pvpython script for visualizing sd_products and sd_attributes. """ From 44a3c32aa6b57c2fc1b89e2177fbbe40f897bf8f Mon Sep 17 00:00:00 2001 From: olastrz Date: Thu, 20 Nov 2025 14:10:07 +0100 Subject: [PATCH 17/29] Remove all pvpython scripts in the pdoc workflow --- .github/workflows/pdoc.yml | 2 +- .../PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pdoc.yml b/.github/workflows/pdoc.yml index af23934bd..7c4261fa8 100644 --- a/.github/workflows/pdoc.yml +++ b/.github/workflows/pdoc.yml @@ -28,7 +28,7 @@ jobs: python-version: "3.12" - name: exclude pvpython scripts - run: rm examples/PySDM_examples/utils/pvanim.py + run: grep -rl '^#!/usr/bin/env pvpython' examples/PySDM_examples | xargs rm -f - run: pip install pdoc nbformat gitpython - run: pip install -e . diff --git a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py index 69f992413..2c32e9c22 100644 --- a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py +++ b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py @@ -1,6 +1,6 @@ +#!/usr/bin/env pvpython """Module for processing PVD files and rendering visualizations using ParaView.""" -#!/usr/bin/env pvpython import argparse from collections import namedtuple import pathlib From 01cedaa984aad2fc73345b11fe54f14bb7606167 Mon Sep 17 00:00:00 2001 From: olastrz Date: Thu, 20 Nov 2025 14:29:10 +0100 Subject: [PATCH 18/29] New artefact for parcel animation and deploy to documentation --- .github/workflows/tests.yml | 4 +++- examples/PySDM_examples/Pyrcel/paraview.ipynb | 8 ++++---- examples/docs/pysdm_examples_landing.md | 4 ++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 52e4d9ee5..ea7e1ca99 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -300,8 +300,10 @@ jobs: rm /tmp/pytest/test_run_notebooks_*current ls /tmp/pytest/test_run_notebooks_*/ ls /tmp/pytest/test_run_notebooks_*/output/ - ffmpeg -i /tmp/pytest/test_run_notebooks_*/output/docs_intro_animation.ogv -loop 0 -vf "fps=10,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" $HOME/work/_temp/_github_home/figures/docs_intro_animation_${{ matrix.platform }}.gif mv /tmp/pytest/test_run_notebooks_*/output/last_animation_frame.pdf $HOME/work/_temp/_github_home/figures/last_animation_frame_${{ matrix.platform }}.pdf + for anim_name in docs_intro_animation parcel_animation; do + ffmpeg -i /tmp/pytest/test_run_notebooks_*/output/${anim_name}.ogv -loop 0 -vf "fps=10,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" $HOME/work/_temp/_github_home/figures/${anim_name}_${{ matrix.platform }}.gif + done ls $HOME/work/_temp/_github_home/figures - name: animation movie upload diff --git a/examples/PySDM_examples/Pyrcel/paraview.ipynb b/examples/PySDM_examples/Pyrcel/paraview.ipynb index e229b6d4f..f96899ebf 100644 --- a/examples/PySDM_examples/Pyrcel/paraview.ipynb +++ b/examples/PySDM_examples/Pyrcel/paraview.ipynb @@ -45,7 +45,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "cd6288b5", "metadata": {}, "outputs": [], @@ -88,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "3ff50a25", "metadata": {}, "outputs": [], @@ -98,7 +98,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "15d59657", "metadata": {}, "outputs": [], @@ -141,7 +141,7 @@ " str(paraview_script),\n", " \"--sd-products-pvd\", str(product),\n", " \"--sd-attributes-pvd\", str(attributes),\n", - " \"--output-animation-path\", str(pathlib.Path(\"./output/animation.avi\").absolute()),\n", + " \"--output-animation-path\", str(pathlib.Path(\"./output/parcel_animation.ogv\").absolute()),\n", " \"--output-screenshot-path\", str(pathlib.Path(\"./output/last_frame.png\").absolute())\n", "]\n", "try:\n", diff --git a/examples/docs/pysdm_examples_landing.md b/examples/docs/pysdm_examples_landing.md index 8479131c9..00a5692ec 100644 --- a/examples/docs/pysdm_examples_landing.md +++ b/examples/docs/pysdm_examples_landing.md @@ -97,6 +97,10 @@ Example notebooks include: The parcel environment is also featured in the PySDM tutorials. +
+ +
+ ## 0D box environment The box environment is void of any spatial or thermodynamic context, it constitutes the most basic framework. From 28509c6f0b997aed0692123ab8a13a8d85ef83cd Mon Sep 17 00:00:00 2001 From: olastrz Date: Fri, 21 Nov 2025 14:29:18 +0100 Subject: [PATCH 19/29] change in notebook, to save frame as pdf not png --- examples/PySDM_examples/Pyrcel/paraview.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/PySDM_examples/Pyrcel/paraview.ipynb b/examples/PySDM_examples/Pyrcel/paraview.ipynb index f96899ebf..84696dba2 100644 --- a/examples/PySDM_examples/Pyrcel/paraview.ipynb +++ b/examples/PySDM_examples/Pyrcel/paraview.ipynb @@ -142,7 +142,7 @@ " \"--sd-products-pvd\", str(product),\n", " \"--sd-attributes-pvd\", str(attributes),\n", " \"--output-animation-path\", str(pathlib.Path(\"./output/parcel_animation.ogv\").absolute()),\n", - " \"--output-screenshot-path\", str(pathlib.Path(\"./output/last_frame.png\").absolute())\n", + " \"--output-screenshot-path\", str(pathlib.Path(\"./output/last_frame.pdf\").absolute())\n", "]\n", "try:\n", " result = subprocess.run(\n", From 5b06e4d61060b08b733e043b5114a12e8f2736bf Mon Sep 17 00:00:00 2001 From: olastrz Date: Fri, 21 Nov 2025 14:47:50 +0100 Subject: [PATCH 20/29] new save screenshot function to ensure pdf format --- .../Pyrcel/paraview_simulation.py | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/examples/PySDM_examples/Pyrcel/paraview_simulation.py b/examples/PySDM_examples/Pyrcel/paraview_simulation.py index 9f5c381a8..2e7ce8714 100644 --- a/examples/PySDM_examples/Pyrcel/paraview_simulation.py +++ b/examples/PySDM_examples/Pyrcel/paraview_simulation.py @@ -6,6 +6,7 @@ import argparse from collections import namedtuple from paraview import simple as pvs # pylint: disable=import-error +import pathlib pvs._DisableFirstRenderCameraReset() # pylint: disable=protected-access @@ -165,7 +166,29 @@ def save_animation_and_screenshot(render_view, animation_path, screenshot_path): animation_scene.UpdateAnimationUsingDataTimeSteps() pvs.SaveAnimation(animation_path, render_view, FrameRate=15) - pvs.SaveScreenshot(screenshot_path, render_view) + + if not screenshot_path: + return + + # set view to last available timestep and update readers before exporting screenshot + time_steps = sd_productspvd.TimestepValues + if not time_steps: + return + + last_time = time_steps[-1] + render_view.ViewTime = last_time + + for reader in (sd_productspvd, sd_attributespvd): + reader.UpdatePipeline(last_time) + + pvs.ExportView( + filename=str(pathlib.Path(screenshot_path)), + view=render_view, + Rasterize3Dgeometry=False, + GL2PSdepthsortmethod="BSP sorting (slow, best)", + ) + + pvs.RenderAllViews() configure_color_bar_and_display( From b2ef45f4557af6f8701eb97007ed5c85e1561ea4 Mon Sep 17 00:00:00 2001 From: olastrz Date: Thu, 27 Nov 2025 11:41:11 +0100 Subject: [PATCH 21/29] New updates consisting of name changes and deleting left comments (https://github.com/open-atmos/PySDM/pull/1725#issuecomment-3565033048) --- PySDM/exporters/parcel_vtk_exporter.py | 113 ++++---- examples/PySDM_examples/Pyrcel/paraview.ipynb | 96 +++---- .../Pyrcel/paraview_parcel_model.py | 244 ++++++++++++++++++ 3 files changed, 352 insertions(+), 101 deletions(-) create mode 100644 examples/PySDM_examples/Pyrcel/paraview_parcel_model.py diff --git a/PySDM/exporters/parcel_vtk_exporter.py b/PySDM/exporters/parcel_vtk_exporter.py index fa034b05f..96557b45d 100644 --- a/PySDM/exporters/parcel_vtk_exporter.py +++ b/PySDM/exporters/parcel_vtk_exporter.py @@ -24,26 +24,26 @@ class VTKExporterPyrcel(VTKExporter): def __init__(self, n_sd, output, mass_of_dry_air): super().__init__() self.output = output - self.x = np.random.random(n_sd) # pylint: disable=invalid-name - self.y = np.random.random(n_sd) # pylint: disable=invalid-name - self.z = np.random.random(n_sd) # pylint: disable=invalid-name + self.x_coords = np.random.random(n_sd) + self.y_coords = np.random.random(n_sd) + self.z_coords = np.random.random(n_sd) self.half_diagonal = [] self.n_levels = len(self.output["products"]["z"]) - _volume = mass_of_dry_air / output["products"]["rhod"][0] - _dz = output["products"]["z"][1] - output["products"]["z"][0] + volume = mass_of_dry_air / output["products"]["rhod"][0] + delta_z = output["products"]["z"][1] - output["products"]["z"][0] for level in range(self.n_levels): if level > 0: prev_to_curr_density_ratio = ( output["products"]["rhod"][level - 1] / output["products"]["rhod"][level] ) - _volume *= prev_to_curr_density_ratio - _dz = ( + volume *= prev_to_curr_density_ratio + delta_z = ( output["products"]["z"][level] - output["products"]["z"][level - 1] ) - _area = _volume / _dz - self.half_diagonal.append((2 * _area) ** 0.5) + area = volume / delta_z + self.half_diagonal.append((2 * area) ** 0.5) def write_pvd(self): pvd_attributes = VtkGroup(self.attributes_file_path) @@ -63,44 +63,62 @@ def export_products( self.exported_times["products"][path] = step * simulation.particulator.dt n_vertices = 4 * self.n_levels - x = np.zeros(n_vertices) # pylint: disable=invalid-name - y = np.zeros(n_vertices) # pylint: disable=invalid-name - z = np.zeros(n_vertices) # pylint: disable=invalid-name - conn = [0, 1, 2, 3] - ctype = np.zeros(self.n_levels - 1) - ctype[:] = VtkHexahedron.tid + x_vertices = np.zeros(n_vertices) + y_vertices = np.zeros(n_vertices) + z_vertices = np.zeros(n_vertices) + connectivity = [0, 1, 2, 3] + cell_type = np.zeros(self.n_levels - 1) + cell_type[:] = VtkHexahedron.tid for level in range(self.n_levels): - hd = self.half_diagonal[level] - _z = self.output["products"]["z"][level] - i = level * 4 - x[i], y[i], z[i] = -hd, -hd, _z - i += 1 - x[i], y[i], z[i] = -hd, hd, _z - i += 1 - x[i], y[i], z[i] = hd, hd, _z - i += 1 - x[i], y[i], z[i] = hd, -hd, _z - conn += [*range(4 * (level + 1), 4 * (level + 2))] * 2 - conn = np.asarray(conn[:-4]) + half_diag = self.half_diagonal[level] + current_z = self.output["products"]["z"][level] + idx = level * 4 + x_vertices[idx], y_vertices[idx], z_vertices[idx] = ( + -half_diag, + -half_diag, + current_z, + ) + idx += 1 + x_vertices[idx], y_vertices[idx], z_vertices[idx] = ( + -half_diag, + half_diag, + current_z, + ) + idx += 1 + x_vertices[idx], y_vertices[idx], z_vertices[idx] = ( + half_diag, + half_diag, + current_z, + ) + idx += 1 + x_vertices[idx], y_vertices[idx], z_vertices[idx] = ( + half_diag, + -half_diag, + current_z, + ) + connectivity += [*range(4 * (level + 1), 4 * (level + 2))] * 2 + connectivity = np.asarray(connectivity[:-4]) offset = np.asarray(range(8, 8 * self.n_levels, 8)) - _ = {"test_pd": np.array([44] * n_vertices)} # pointData + _ = {"test_pd": np.array([44] * n_vertices)} - _RH = self.output["products"]["S_max_percent"] # pylint: disable=invalid-name - cell_data = {"RH": np.full(shape=(len(_RH) - 1,), fill_value=np.nan)} - cell_data["RH"][:step] = (np.array(_RH[:-1] + np.diff(_RH) / 2))[:step] + relative_humidity = self.output["products"]["S_max_percent"] + cell_data = { + "RH": np.full(shape=(len(relative_humidity) - 1,), fill_value=np.nan) + } + cell_data["RH"][:step] = ( + np.array(relative_humidity[:-1] + np.diff(relative_humidity) / 2) + )[:step] unstructuredGridToVTK( path, - x, - y, - z, - connectivity=conn, + x_vertices, + y_vertices, + z_vertices, + connectivity=connectivity, offsets=offset, - cell_types=ctype, + cell_types=cell_type, cellData=cell_data, - # pointData=point_data, - # fieldData=field_data, ) def export_attributes(self, step, simulation): # pylint: disable=arguments-differ @@ -109,23 +127,22 @@ def export_attributes(self, step, simulation): # pylint: disable=arguments-diff payload = {} - for k in self.output["attributes"].keys(): - payload[k] = np.asarray(self.output["attributes"][k])[:, step].copy() - # payload["size"] = np.full(simulation.particulator.n_sd, 100.0) + for key in self.output["attributes"].keys(): + payload[key] = np.asarray(self.output["attributes"][key])[:, step].copy() if step != 0: - dz = ( + delta_z = ( self.output["products"]["z"][step] - self.output["products"]["z"][step - 1] - ) # pylint: disable=invalid-name + ) if step == 1: - self.z *= dz + self.z_coords *= delta_z else: - self.z += dz + self.z_coords += delta_z pointsToVTK( path, - 2 * (self.x - 0.5) * self.half_diagonal[step], - 2 * (self.y - 0.5) * self.half_diagonal[step], - self.z, + 2 * (self.x_coords - 0.5) * self.half_diagonal[step], + 2 * (self.y_coords - 0.5) * self.half_diagonal[step], + self.z_coords, data=payload, ) diff --git a/examples/PySDM_examples/Pyrcel/paraview.ipynb b/examples/PySDM_examples/Pyrcel/paraview.ipynb index 84696dba2..b752d0e2f 100644 --- a/examples/PySDM_examples/Pyrcel/paraview.ipynb +++ b/examples/PySDM_examples/Pyrcel/paraview.ipynb @@ -5,16 +5,10 @@ "execution_count": 1, "id": "6dcbcc6d", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c:\\Users\\strza\\Desktop\\PySDM\\examples\\PySDM_examples\\Pyrcel\\../../../PySDM/exporters/\n" - ] - } - ], + "outputs": [], "source": [ + "\"\"\"Run Pyrcel simulation and export Paraview files.\"\"\"\n", + "\n", "import numpy as np\n", "import subprocess\n", "import platform\n", @@ -32,15 +26,8 @@ ")\n", "\n", "from PySDM_examples.Pyrcel import Settings, Simulation\n", - "import sys\n", - "import os\n", "\n", - "notebook_dir = os.path.dirname(os.path.abspath(\"__file__\"))\n", - "exporters_path = os.path.join(notebook_dir, \"../../../PySDM/exporters/\")\n", - "print(exporters_path)\n", - "sys.path.append(exporters_path)\n", - "\n", - "from parcel_vtk_exporter import VTKExporterPyrcel #pylint: disable=import-error" + "from PySDM.exporters.parcel_vtk_exporter import VTKExporterPyrcel" ] }, { @@ -54,8 +41,16 @@ " dz=10 * si.m,\n", " n_sd_per_mode=(25, 25),\n", " aerosol_modes_by_kappa={\n", - " 0.54: Lognormal(norm_factor=850 / si.cm**3, m_mode=15 * si.nm, s_geom=1.6),\n", - " 1.2: Lognormal(norm_factor=10 / si.cm**3, m_mode=850 * si.nm, s_geom=1.2),\n", + " 0.54: Lognormal(\n", + " norm_factor=850 / si.cm**3,\n", + " m_mode=15 * si.nm,\n", + " s_geom=1.6,\n", + " ),\n", + " 1.2: Lognormal(\n", + " norm_factor=10 / si.cm**3,\n", + " m_mode=850 * si.nm,\n", + " s_geom=1.2,\n", + " ),\n", " },\n", " vertical_velocity=1.0 * si.m / si.s,\n", " initial_pressure=775 * si.mbar,\n", @@ -101,7 +96,19 @@ "execution_count": 4, "id": "15d59657", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "TypeError", + "evalue": "VTKExporterPyrcel.export_products() takes 2 positional arguments but 3 were given", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[4], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m e \u001b[38;5;241m=\u001b[39m VTKExporterPyrcel(n_sd\u001b[38;5;241m=\u001b[39msimulation\u001b[38;5;241m.\u001b[39mparticulator\u001b[38;5;241m.\u001b[39mn_sd, output\u001b[38;5;241m=\u001b[39moutput, mass_of_dry_air\u001b[38;5;241m=\u001b[39msimulation\u001b[38;5;241m.\u001b[39mparticulator\u001b[38;5;241m.\u001b[39menvironment\u001b[38;5;241m.\u001b[39mmass_of_dry_air)\n\u001b[0;32m 2\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m step \u001b[38;5;129;01min\u001b[39;00m settings\u001b[38;5;241m.\u001b[39moutput_steps:\n\u001b[1;32m----> 3\u001b[0m e\u001b[38;5;241m.\u001b[39mexport_products(step, simulation)\n\u001b[0;32m 4\u001b[0m e\u001b[38;5;241m.\u001b[39mexport_attributes(step, simulation)\n\u001b[0;32m 5\u001b[0m e\u001b[38;5;241m.\u001b[39mwrite_pvd()\n", + "\u001b[1;31mTypeError\u001b[0m: VTKExporterPyrcel.export_products() takes 2 positional arguments but 3 were given" + ] + } + ], "source": [ "e = VTKExporterPyrcel(n_sd=simulation.particulator.n_sd, output=output, mass_of_dry_air=simulation.particulator.environment.mass_of_dry_air)\n", "for step in settings.output_steps:\n", @@ -115,49 +122,32 @@ "execution_count": null, "id": "4a6ea0e6", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Script paraview_simulation.py executed successfully.\n", - "STDOUT: VisRTX 0.1.6, using devices:\n", - " 0: NVIDIA GeForce RTX 4050 Laptop GPU (Total: 6.4 GB, Available: 5.3 GB)\n", - "\n" - ] - } - ], + "outputs": [], "source": [ - "\n", - "\n", "product = pathlib.Path(\"./output/sd_products.pvd\").absolute()\n", "attributes = pathlib.Path(\"./output/sd_attributes.pvd\").absolute()\n", "\n", - "paraview_script = pathlib.Path(\"./paraview_simulation.py\").absolute()\n", + "paraview_script = pathlib.Path(\"./paraview_parcel_model.py\").absolute()\n", "\n", "args = [\n", " \"pvpython\",\n", " \"--force-offscreen-rendering\",\n", " str(paraview_script),\n", - " \"--sd-products-pvd\", str(product),\n", - " \"--sd-attributes-pvd\", str(attributes),\n", - " \"--output-animation-path\", str(pathlib.Path(\"./output/parcel_animation.ogv\").absolute()),\n", - " \"--output-screenshot-path\", str(pathlib.Path(\"./output/last_frame.pdf\").absolute())\n", + " \"--sd-products-pvd\",\n", + " str(product),\n", + " \"--sd-attributes-pvd\",\n", + " str(attributes),\n", + " \"--output-animation-path\",\n", + " str(pathlib.Path(\"./output/parcel_animation.ogv\").absolute()),\n", + " \"--output-screenshot-path\",\n", + " str(pathlib.Path(\"./output/last_frame.pdf\").absolute()),\n", "]\n", - "try:\n", - " result = subprocess.run(\n", - " args,\n", - " check=platform.system() != \"Windows\",\n", - " capture_output=True,\n", - " text=True,\n", - " )\n", - " print(\"Script paraview_simulation.py executed successfully.\")\n", - " if result.stdout:\n", - " print(\"STDOUT:\", result.stdout)\n", - "except subprocess.CalledProcessError as e:\n", - " print(\"Error during script execution:\")\n", - " print(\"STDERR:\", e.stderr)\n", - " print(\"STDOUT:\", e.stdout)" + "result = subprocess.run(\n", + " args,\n", + " check=platform.system() != \"Windows\",\n", + " capture_output=True,\n", + " text=True,\n", + ")" ] } ], diff --git a/examples/PySDM_examples/Pyrcel/paraview_parcel_model.py b/examples/PySDM_examples/Pyrcel/paraview_parcel_model.py new file mode 100644 index 000000000..953e9eab0 --- /dev/null +++ b/examples/PySDM_examples/Pyrcel/paraview_parcel_model.py @@ -0,0 +1,244 @@ +#!/usr/bin/env pvpython +""" +ParaView pvpython script for visualizing sd_products and sd_attributes. +""" + +import argparse +from collections import namedtuple +import pathlib +from paraview import simple as pvs # pylint: disable=import-error + +pvs._DisableFirstRenderCameraReset() # pylint: disable=protected-access + + +def cli_using_argparse(argparse_parser): + """ + Command line interface using argparse. + """ + argparse_parser.add_argument( + "--sd-products-pvd", + dest="sd_products_pvd", + help="Path to sd_products.pvd", + ) + argparse_parser.add_argument( + "--sd-attributes-pvd", + dest="sd_attributes_pvd", + help="Path to sd_attributes.pvd", + ) + argparse_parser.add_argument( + "--output-animation-path", + help="Output path for the animation file.", + ) + argparse_parser.add_argument( + "--output-screenshot-path", + help="Output path for the screenshot file.", + ) + + argparse_parser.add_argument( + "--scalarbar-title-size", + type=int, + default=30, + help="Font size for scalar bar titles.", + ) + argparse_parser.add_argument( + "--scalarbar-label-size", + type=int, + default=30, + help="Font size for scalar bar labels.", + ) + argparse_parser.add_argument( + "--axes-title-size", + type=int, + default=30, + help="Font size for axes titles.", + ) + argparse_parser.add_argument( + "--axes-label-size", + type=int, + default=30, + help="Font size for axes labels.", + ) + + +parser = argparse.ArgumentParser( + description="ParaView pvpython script for visualizing sd_products and sd_attributes PVD files." +) +cli_using_argparse(parser) +args = parser.parse_args() + +sd_productspvd = pvs.PVDReader( + registrationName="sd_products.pvd", FileName=args.sd_products_pvd +) +sd_attributespvd = pvs.PVDReader( + registrationName="sd_attributes.pvd", FileName=args.sd_attributes_pvd +) + +setup = { + "renderView1": pvs.GetActiveViewOrCreate("RenderView"), + "sd_productspvdDisplay": pvs.Show( + sd_productspvd, + pvs.GetActiveViewOrCreate("RenderView"), + "UnstructuredGridRepresentation", + ), + "sd_attributespvdDisplay": pvs.Show( + sd_attributespvd, + pvs.GetActiveViewOrCreate("RenderView"), + "UnstructuredGridRepresentation", + ), + "rHlookup_table": pvs.GetColorTransferFunction("RH"), + "volumelookup_table": pvs.GetColorTransferFunction("volume"), +} + +animation_setup = namedtuple("setup", setup.keys())(**setup) + + +def configure_color_bar_and_display( + display, lookup_table, kind, *, anim_setup=animation_setup +): + """ + Configure color bar and display settings. + """ + display.Representation = "Surface" + display.SetScalarBarVisibility(anim_setup.renderView1, True) + color_bar = pvs.GetScalarBar(lookup_table, anim_setup.renderView1) + color_bar.LabelColor = [0.0, 0.0, 0.0] + color_bar.DrawScalarBarOutline = 1 + color_bar.ScalarBarOutlineColor = [0.0, 0.0, 0.0] + color_bar.TitleColor = [0.0, 0.0, 0.0] + + color_bar.TitleFontSize = args.scalarbar_title_size + color_bar.LabelFontSize = args.scalarbar_label_size + + if kind == "prod": + display.Opacity = 0.4 + display.DisableLighting = 1 + display.Diffuse = 0.76 + lookup_table.RescaleTransferFunction(90.0, 101.0) + lookup_table.ApplyPreset("Black, Blue and White", True) + lookup_table.NanColor = [0.67, 1.0, 1.0] + else: + display.PointSize = 13.0 + display.RenderPointsAsSpheres = 1 + display.Interpolation = "PBR" + lookup_table.RescaleTransferFunction(1e-18, 1e-13) + lookup_table.ApplyPreset("Cold and Hot", True) + lookup_table.MapControlPointsToLogSpace() + lookup_table.UseLogScale = 1 + lookup_table.NumberOfTableValues = 16 + lookup_table.InvertTransferFunction() + + +def configure_data_axes_grid(display, kind): + """ + Configure data axes grid settings. + """ + display.DataAxesGrid.GridAxesVisibility = 1 + display.DataAxesGrid.XTitle = "" + display.DataAxesGrid.YTitle = "" + display.DataAxesGrid.XAxisUseCustomLabels = 1 + display.DataAxesGrid.YAxisUseCustomLabels = 1 + + display.DataAxesGrid.XTitleFontSize = args.axes_title_size + display.DataAxesGrid.XLabelFontSize = args.axes_label_size + display.DataAxesGrid.YTitleFontSize = args.axes_title_size + display.DataAxesGrid.YLabelFontSize = args.axes_label_size + + if kind == "prod": + display.DataAxesGrid.ZTitle = "" + display.DataAxesGrid.GridColor = [0.0, 0.0, 0.0] + display.DataAxesGrid.ShowGrid = 1 + display.DataAxesGrid.LabelUniqueEdgesOnly = 0 + display.DataAxesGrid.ZAxisUseCustomLabels = 1 + display.DataAxesGrid.ZTitleFontSize = args.axes_title_size + display.DataAxesGrid.ZLabelFontSize = args.axes_label_size + else: + display.DataAxesGrid.ZTitle = "Z [m]" + display.DataAxesGrid.ZLabelColor = [0.0, 0.0, 0.0] + display.DataAxesGrid.ZTitleColor = [0.0, 0.0, 0.0] + display.DataAxesGrid.ZTitleFontSize = args.axes_title_size + display.DataAxesGrid.ZLabelFontSize = args.axes_label_size + + +def configure_view_appearance(render_view): + """ + Configure view appearance settings.""" + render_view.OrientationAxesLabelColor = [0.0, 0.0, 0.0] + render_view.OrientationAxesOutlineColor = [0.0, 0.0, 0.0] + render_view.OrientationAxesXVisibility = 0 + render_view.OrientationAxesYVisibility = 0 + render_view.OrientationAxesZColor = [0.0, 0.0, 0.0] + render_view.UseColorPaletteForBackground = 0 + render_view.Background = [1.0, 1.0, 1.0] + + +def set_camera_view(render_view): + """ + Set camera view settings. + """ + layout1 = pvs.GetLayout() + layout1.SetSize(1592, 1128) + render_view.CameraPosition = [ + 1548.95, + -1349.49, + 699.27, + ] + render_view.CameraFocalPoint = [ + -1.37e-13, + 3.18e-13, + 505.00, + ] + render_view.CameraViewUp = [ + -0.07, + 0.06, + 0.99, + ] + render_view.CameraParallelScale = 534.08 + + +def save_animation_and_screenshot(render_view, animation_path, screenshot_path): + """ + Save animation and screenshot. + """ + animation_scene = pvs.GetAnimationScene() + animation_scene.UpdateAnimationUsingDataTimeSteps() + + pvs.SaveAnimation(animation_path, render_view, FrameRate=15) + + if not screenshot_path: + return + + time_steps = sd_productspvd.TimestepValues + if not time_steps: + return + + last_time = time_steps[-1] + render_view.ViewTime = last_time + + for reader in (sd_productspvd, sd_attributespvd): + reader.UpdatePipeline(last_time) + + pvs.ExportView( + filename=str(pathlib.Path(screenshot_path)), + view=render_view, + Rasterize3Dgeometry=False, + GL2PSdepthsortmethod="BSP sorting (slow, best)", + ) + + pvs.RenderAllViews() + + +configure_color_bar_and_display( + animation_setup.sd_productspvdDisplay, animation_setup.rHlookup_table, kind="prod" +) +configure_data_axes_grid(animation_setup.sd_productspvdDisplay, kind="prod") +configure_view_appearance(animation_setup.renderView1) +configure_color_bar_and_display( + animation_setup.sd_attributespvdDisplay, + animation_setup.volumelookup_table, + kind="attr", +) +configure_data_axes_grid(animation_setup.sd_attributespvdDisplay, kind="attr") +set_camera_view(animation_setup.renderView1) +save_animation_and_screenshot( + animation_setup.renderView1, args.output_animation_path, args.output_screenshot_path +) From baefbe550621137f083c5f8268860d63c8fef822 Mon Sep 17 00:00:00 2001 From: olastrz Date: Thu, 27 Nov 2025 17:07:46 +0100 Subject: [PATCH 22/29] New unit test and updates (consisted with this comment: https://github.com/open-atmos/PySDM/pull/1725#issuecomment-3565033048) --- .../Pyrcel/paraview_simulation.py | 208 ---------- examples/PySDM_examples/Pyrcel/simulation.py | 10 +- .../Strzabala_2025_BEng/__init__.py | 8 + .../paraview.ipynb | 19 +- .../paraview_parcel_model.py | 0 .../__init__.py | 0 .../calc2.py | 352 ----------------- .../no_glyphs.py | 362 ------------------ examples/docs/pysdm_examples_landing.md | 1 + .../exporters/test_parcel_vtk_exporter.py | 205 ++++++++++ 10 files changed, 226 insertions(+), 939 deletions(-) delete mode 100644 examples/PySDM_examples/Pyrcel/paraview_simulation.py create mode 100644 examples/PySDM_examples/Strzabala_2025_BEng/__init__.py rename examples/PySDM_examples/{Pyrcel => Strzabala_2025_BEng}/paraview.ipynb (76%) rename examples/PySDM_examples/{Pyrcel => Strzabala_2025_BEng}/paraview_parcel_model.py (100%) delete mode 100644 examples/PySDM_examples/Strzabala_engineering_thesis_2025/__init__.py delete mode 100644 examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py delete mode 100644 examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py create mode 100644 tests/unit_tests/exporters/test_parcel_vtk_exporter.py diff --git a/examples/PySDM_examples/Pyrcel/paraview_simulation.py b/examples/PySDM_examples/Pyrcel/paraview_simulation.py deleted file mode 100644 index 2e7ce8714..000000000 --- a/examples/PySDM_examples/Pyrcel/paraview_simulation.py +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env pvpython -""" -ParaView pvpython script for visualizing sd_products and sd_attributes. -""" - -import argparse -from collections import namedtuple -from paraview import simple as pvs # pylint: disable=import-error -import pathlib - -pvs._DisableFirstRenderCameraReset() # pylint: disable=protected-access - - -def cli_using_argparse(argparse_parser): - """ - Command line interface using argparse. - """ - argparse_parser.add_argument( - "--sd-products-pvd", - dest="sd_products_pvd", - help="Path to sd_products.pvd", - ) - argparse_parser.add_argument( - "--sd-attributes-pvd", - dest="sd_attributes_pvd", - help="Path to sd_attributes.pvd", - ) - argparse_parser.add_argument( - "--output-animation-path", - help="Output path for the animation file.", - ) - argparse_parser.add_argument( - "--output-screenshot-path", - help="Output path for the screenshot file.", - ) - - -parser = argparse.ArgumentParser( - description="ParaView pvpython script for visualizing sd_products and sd_attributes PVD files." -) -cli_using_argparse(parser) -args = parser.parse_args() - -sd_productspvd = pvs.PVDReader( - registrationName="sd_products.pvd", FileName=args.sd_products_pvd -) -sd_attributespvd = pvs.PVDReader( - registrationName="sd_attributes.pvd", FileName=args.sd_attributes_pvd -) - -setup = { - "renderView1": pvs.GetActiveViewOrCreate("RenderView"), - "sd_productspvdDisplay": pvs.Show( - sd_productspvd, - pvs.GetActiveViewOrCreate("RenderView"), - "UnstructuredGridRepresentation", - ), - "sd_attributespvdDisplay": pvs.Show( - sd_attributespvd, - pvs.GetActiveViewOrCreate("RenderView"), - "UnstructuredGridRepresentation", - ), - "rHlookup_table": pvs.GetColorTransferFunction("RH"), - "volumelookup_table": pvs.GetColorTransferFunction("volume"), -} - -animation_setup = namedtuple("setup", setup.keys())(**setup) - - -def configure_color_bar_and_display( - display, lookup_table, kind, *, anim_setup=animation_setup -): - """ - Configure color bar and display settings. - """ - display.Representation = "Surface" - display.SetScalarBarVisibility(anim_setup.renderView1, True) - color_bar = pvs.GetScalarBar(lookup_table, anim_setup.renderView1) - color_bar.LabelColor = [0.0, 0.0, 0.0] - color_bar.DrawScalarBarOutline = 1 - color_bar.ScalarBarOutlineColor = [0.0, 0.0, 0.0] - color_bar.TitleColor = [0.0, 0.0, 0.0] - - if kind == "prod": - display.Opacity = 0.4 - display.DisableLighting = 1 - display.Diffuse = 0.76 - lookup_table.RescaleTransferFunction(90.0, 101.0) - lookup_table.ApplyPreset("Black, Blue and White", True) - lookup_table.NanColor = [0.67, 1.0, 1.0] - else: - display.PointSize = 13.0 - display.RenderPointsAsSpheres = 1 - display.Interpolation = "PBR" - lookup_table.RescaleTransferFunction(1e-18, 1e-13) - lookup_table.ApplyPreset("Cold and Hot", True) - lookup_table.MapControlPointsToLogSpace() - lookup_table.UseLogScale = 1 - lookup_table.NumberOfTableValues = 16 - lookup_table.InvertTransferFunction() - - -def configure_data_axes_grid(display, kind): - """ - Configure data axes grid settings. - """ - display.DataAxesGrid.GridAxesVisibility = 1 - display.DataAxesGrid.XTitle = "" - display.DataAxesGrid.YTitle = "" - display.DataAxesGrid.XAxisUseCustomLabels = 1 - display.DataAxesGrid.YAxisUseCustomLabels = 1 - - if kind == "prod": - display.DataAxesGrid.ZTitle = "" - display.DataAxesGrid.GridColor = [0.0, 0.0, 0.0] - display.DataAxesGrid.ShowGrid = 1 - display.DataAxesGrid.LabelUniqueEdgesOnly = 0 - display.DataAxesGrid.ZAxisUseCustomLabels = 1 - else: - display.DataAxesGrid.ZTitle = "Z [m]" - display.DataAxesGrid.ZLabelColor = [0.0, 0.0, 0.0] - display.DataAxesGrid.ZTitleColor = [0.0, 0.0, 0.0] - - -def configure_view_appearance(render_view): - """ - Configure view appearance settings.""" - render_view.OrientationAxesLabelColor = [0.0, 0.0, 0.0] - render_view.OrientationAxesOutlineColor = [0.0, 0.0, 0.0] - render_view.OrientationAxesXVisibility = 0 - render_view.OrientationAxesYVisibility = 0 - render_view.OrientationAxesZColor = [0.0, 0.0, 0.0] - render_view.UseColorPaletteForBackground = 0 - render_view.Background = [1.0, 1.0, 1.0] - - -def set_camera_view(render_view): - """ - Set camera view settings. - """ - layout1 = pvs.GetLayout() - layout1.SetSize(1592, 1128) - render_view.CameraPosition = [ - 1548.945972263949, - -1349.493616194682, - 699.2699178747185, - ] - render_view.CameraFocalPoint = [ - -1.3686701146742275e-13, - 3.1755031232028544e-13, - 505.00000000000017, - ] - render_view.CameraViewUp = [ - -0.07221292769632315, - 0.06043215330151439, - 0.9955567527373153, - ] - render_view.CameraParallelScale = 534.07781536883 - - -def save_animation_and_screenshot(render_view, animation_path, screenshot_path): - """ - Save animation and screenshot. - """ - animation_scene = pvs.GetAnimationScene() - animation_scene.UpdateAnimationUsingDataTimeSteps() - - pvs.SaveAnimation(animation_path, render_view, FrameRate=15) - - if not screenshot_path: - return - - # set view to last available timestep and update readers before exporting screenshot - time_steps = sd_productspvd.TimestepValues - if not time_steps: - return - - last_time = time_steps[-1] - render_view.ViewTime = last_time - - for reader in (sd_productspvd, sd_attributespvd): - reader.UpdatePipeline(last_time) - - pvs.ExportView( - filename=str(pathlib.Path(screenshot_path)), - view=render_view, - Rasterize3Dgeometry=False, - GL2PSdepthsortmethod="BSP sorting (slow, best)", - ) - - pvs.RenderAllViews() - - -configure_color_bar_and_display( - animation_setup.sd_productspvdDisplay, animation_setup.rHlookup_table, kind="prod" -) -configure_data_axes_grid(animation_setup.sd_productspvdDisplay, kind="prod") -configure_view_appearance(animation_setup.renderView1) -configure_color_bar_and_display( - animation_setup.sd_attributespvdDisplay, - animation_setup.volumelookup_table, - kind="attr", -) -configure_data_axes_grid(animation_setup.sd_attributespvdDisplay, kind="attr") -set_camera_view(animation_setup.renderView1) -save_animation_and_screenshot( - animation_setup.renderView1, args.output_animation_path, args.output_screenshot_path -) diff --git a/examples/PySDM_examples/Pyrcel/simulation.py b/examples/PySDM_examples/Pyrcel/simulation.py index e631c347b..a65d22d95 100644 --- a/examples/PySDM_examples/Pyrcel/simulation.py +++ b/examples/PySDM_examples/Pyrcel/simulation.py @@ -13,7 +13,13 @@ class Simulation(BasicSimulation): def __init__( - self, settings, products=None, scipy_solver=False, rtol_thd=1e-10, rtol_x=1e-10 + self, + settings, + products=None, + scipy_solver=False, + rtol_thd=1e-10, + rtol_x=1e-10, + mass_of_dry_air=44 * si.kg, ): n_sd = sum(settings.n_sd_per_mode) builder = Builder( @@ -27,7 +33,7 @@ def __init__( initial_water_vapour_mixing_ratio=settings.initial_vapour_mixing_ratio, T0=settings.initial_temperature, w=settings.vertical_velocity, - mass_of_dry_air=66666 * si.kg, + mass_of_dry_air=mass_of_dry_air, ), ) builder.add_dynamic(AmbientThermodynamics()) diff --git a/examples/PySDM_examples/Strzabala_2025_BEng/__init__.py b/examples/PySDM_examples/Strzabala_2025_BEng/__init__.py new file mode 100644 index 000000000..224822c35 --- /dev/null +++ b/examples/PySDM_examples/Strzabala_2025_BEng/__init__.py @@ -0,0 +1,8 @@ +# pylint: disable=invalid-name +""" +ParaView visualisation of a parcel-model example based on the test case from +[Pyrcel package docs](https://pyrcel.readthedocs.io/) + +paraview_parcel_model.ipynb: +.. include:: ./paraview_parcel_model.ipynb.badges.md +""" diff --git a/examples/PySDM_examples/Pyrcel/paraview.ipynb b/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb similarity index 76% rename from examples/PySDM_examples/Pyrcel/paraview.ipynb rename to examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb index b752d0e2f..2ec8f17e0 100644 --- a/examples/PySDM_examples/Pyrcel/paraview.ipynb +++ b/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb @@ -32,7 +32,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "cd6288b5", "metadata": {}, "outputs": [], @@ -78,6 +78,7 @@ " ),\n", " AmbientDryAirDensity(),\n", " ),\n", + " mass_of_dry_air = 66666 * si.kg,\n", ")" ] }, @@ -96,19 +97,7 @@ "execution_count": 4, "id": "15d59657", "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "VTKExporterPyrcel.export_products() takes 2 positional arguments but 3 were given", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[4], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m e \u001b[38;5;241m=\u001b[39m VTKExporterPyrcel(n_sd\u001b[38;5;241m=\u001b[39msimulation\u001b[38;5;241m.\u001b[39mparticulator\u001b[38;5;241m.\u001b[39mn_sd, output\u001b[38;5;241m=\u001b[39moutput, mass_of_dry_air\u001b[38;5;241m=\u001b[39msimulation\u001b[38;5;241m.\u001b[39mparticulator\u001b[38;5;241m.\u001b[39menvironment\u001b[38;5;241m.\u001b[39mmass_of_dry_air)\n\u001b[0;32m 2\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m step \u001b[38;5;129;01min\u001b[39;00m settings\u001b[38;5;241m.\u001b[39moutput_steps:\n\u001b[1;32m----> 3\u001b[0m e\u001b[38;5;241m.\u001b[39mexport_products(step, simulation)\n\u001b[0;32m 4\u001b[0m e\u001b[38;5;241m.\u001b[39mexport_attributes(step, simulation)\n\u001b[0;32m 5\u001b[0m e\u001b[38;5;241m.\u001b[39mwrite_pvd()\n", - "\u001b[1;31mTypeError\u001b[0m: VTKExporterPyrcel.export_products() takes 2 positional arguments but 3 were given" - ] - } - ], + "outputs": [], "source": [ "e = VTKExporterPyrcel(n_sd=simulation.particulator.n_sd, output=output, mass_of_dry_air=simulation.particulator.environment.mass_of_dry_air)\n", "for step in settings.output_steps:\n", @@ -119,7 +108,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "4a6ea0e6", "metadata": {}, "outputs": [], diff --git a/examples/PySDM_examples/Pyrcel/paraview_parcel_model.py b/examples/PySDM_examples/Strzabala_2025_BEng/paraview_parcel_model.py similarity index 100% rename from examples/PySDM_examples/Pyrcel/paraview_parcel_model.py rename to examples/PySDM_examples/Strzabala_2025_BEng/paraview_parcel_model.py diff --git a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/__init__.py b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py deleted file mode 100644 index 2c32e9c22..000000000 --- a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/calc2.py +++ /dev/null @@ -1,352 +0,0 @@ -#!/usr/bin/env pvpython -"""Module for processing PVD files and rendering visualizations using ParaView.""" - -import argparse -from collections import namedtuple -import pathlib - -from paraview import simple as pvs # pylint: disable=import-error - -pvs._DisableFirstRenderCameraReset() # pylint: disable=protected-access - - -def cli_using_argparse(argp): - """Set up command line argument parsing.""" - argp.add_argument("product_path", help="path to pvd products file") - argp.add_argument("attributes_path", help=" path to pvd attributes file") - argp.add_argument("output_path", help="path where to write output files") - argp.add_argument( - "--mode", - choices=["light", "dark"], - default="light", - help="Choose 'light' or 'dark' mode.", - ) - argp.add_argument( - "--multiplicity_preset", - default="Inferno (matplotlib)", - help="Preset for multiplicity", - ) - argp.add_argument( - "--multiplicity_logscale", - action="store_false", - help="Use log scale for multiplicity", - ) - argp.add_argument( - "--effectiveradius_preset", - default="Black, Blue and White", - help="Preset for effectiveradius", - ) - argp.add_argument( - "--effectiveradius_logscale", - action="store_false", - help="Use log scale for effectiveradius", - ) - argp.add_argument( - "--effectiveradius_nan_color", - nargs=3, - type=float, - default=[0.666, 0.333, 1.0], - help="Nan color in RGB format for effectiveradius", - ) - argp.add_argument( - "--sd_products_opacity", type=float, default=0.0, help="Opacity for sd_products" - ) - argp.add_argument( - "--calculator1_opacity", - type=float, - default=0.0, - help="Opacity for calculator1", - ) - argp.add_argument( - "--sd_attributes_opacity", - type=float, - default=0.0, - help="Opacity for sd_attributes", - ) - argp.add_argument( - "--animation_size", - nargs=2, - type=int, - default=[800, 800], - help="Animation size [x,y]", - ) - argp.add_argument( - "--animationframename", - type=str, - help="Name of the file with animation last frame", - ) - argp.add_argument( - "--animationname", - type=str, - help="Name of the file with animation", - ) - argp.add_argument( - "--framerate", type=int, help="Number of frame rates.", default=15 - ) - - -ap = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) -cli_using_argparse(ap) - -args = ap.parse_args() -sd_productspvd = pvs.OpenDataFile(args.product_path) -sd_attributespvd = pvs.OpenDataFile(args.attributes_path) - - -setup = { - "renderView1": pvs.GetActiveViewOrCreate("RenderView"), - "sd_attributespvdDisplay": pvs.GetDisplayProperties( - sd_attributespvd, view=pvs.GetActiveViewOrCreate("RenderView") - ), - "effectiveradiusLUT": pvs.GetColorTransferFunction("effectiveradius"), - "sd_productspvdDisplay": pvs.GetDisplayProperties( - sd_productspvd, view=pvs.GetActiveViewOrCreate("RenderView") - ), - "color": [1, 1, 1] if args.mode == "dark" else [0, 0, 0], - "inverted_color": [0.129, 0.145, 0.161] if args.mode == "dark" else [1, 1, 1], -} - -setup = namedtuple("Setup", setup.keys())(**setup) - -setup.effectiveradiusLUT.RescaleTransferFunction(0.1380997175392798, 207.7063518856934) -materialLibrary1 = pvs.GetMaterialLibrary() -setup.renderView1.Update() - - -def create_new_calculator(params): - """Create a new calculator in ParaView.""" - calcinput = params["calcinput"] - representation = params["representation"] - function = params["function"] - color_by1 = params["color_by1"] - color_by2 = params["color_by2"] - color_by3 = params["color_by3"] - scalar_coloring = params.get("scalar_coloring", False) - hide = params.get("hide", False) - setup_context = params["setup_context"] - registration_name = params["registration_name"] - - calculator = pvs.Calculator(registrationName=registration_name, Input=calcinput) - display = pvs.Show(calculator, setup_context.renderView1, representation) - calculator.Function = function - setup_context.renderView1.Update() - if scalar_coloring: - pvs.ColorBy(display, (color_by1, color_by2, color_by3)) - if hide: - pvs.Hide(calculator, setup_context.renderView1) - return setup_context.renderView1.Update() - - -def scalar_bar(name, *, y, erLUT): - """Display a scalar bar for the given name.""" - calculator1_display = pvs.Show( - calculator1, y.renderView1, "UnstructuredGridRepresentation" - ) - calculator1_display.SetScalarBarVisibility(y.renderView1, True) - scalar_bar_instance = pvs.GetScalarBar(erLUT.effectiveradiusLUT, y.renderView1) - scalar_bar_instance.ComponentTitle = "" - scalar_bar_instance.Title = name - scalar_bar_instance.TitleFontSize = 25 - scalar_bar_instance.LabelFontSize = 25 - scalar_bar_instance.LabelColor = setup.color - scalar_bar_instance.TitleColor = setup.color - pvs.Hide(scalar_bar_instance) - y.renderView1.Update() - - -def create_glyph(params): - """Create a glyph representation in ParaView.""" - registration_name = params["registration_name"] - put = params["put"] - scale_array1 = params["scale_array1"] - scale_array2 = params["scale_array2"] - color_by = params.get("color_by", False) - - glyph = pvs.Glyph(registrationName=registration_name, Input=put, GlyphType="Arrow") - glyph_display = pvs.Show(glyph, setup.renderView1, "GeometryRepresentation") - glyph_display.Representation = "Surface" - glyph.ScaleArray = [scale_array1, scale_array2] - glyph.ScaleFactor = 100 - glyph_display.SetScalarBarVisibility(setup.renderView1, True) - - multiplicity_lut = pvs.GetColorTransferFunction("multiplicity") - multiplicity_lut_color_bar = pvs.GetScalarBar(multiplicity_lut, setup.renderView1) - multiplicity_lut_color_bar.Position = [0.5, 0.9] - multiplicity_lut_color_bar.TitleFontSize = 25 - multiplicity_lut_color_bar.LabelFontSize = 25 - multiplicity_lut_color_bar.LabelColor = setup.color - multiplicity_lut_color_bar.TitleColor = setup.color - - if color_by: - glyph_display.ColorArrayName = ["POINTS", ""] - pvs.ColorBy(glyph_display, None) - - setup.renderView1.Update() - - -def apply_presets_logscale_opacity_and_update(*, y, attdisplay, erLUT, proddisplay): - """Apply presets, log scale, opacity settings, and update the view.""" - multiplicity_lut = pvs.GetColorTransferFunction("multiplicity") - multiplicity_lut.RescaleTransferFunction(19951.0, 50461190157.0) - calculator1_display = pvs.Show( - calculator1, y.renderView1, "UnstructuredGridRepresentation" - ) - multiplicity_lut.ApplyPreset(args.multiplicity_preset, True) - if args.multiplicity_logscale: - multiplicity_lut.MapControlPointsToLogSpace() - multiplicity_lut.UseLogScale = 1 - else: - multiplicity_lut.MapControlPointsToLinearSpace() - multiplicity_lut.UseLogScale = 0 - - erLUT.effectiveradiusLUT.ApplyPreset(args.effectiveradius_preset, True) - if args.effectiveradius_logscale: - erLUT.effectiveradiusLUT.MapControlPointsToLogSpace() - erLUT.effectiveradiusLUT.UseLogScale = 1 - else: - erLUT.effectiveradiusLUT.MapControlPointsToLinearSpace() - erLUT.effectiveradiusLUT.UseLogScale = 0 - - erLUT.effectiveradiusLUT.NanColor = args.effectiveradius_nan_color - proddisplay.sd_productspvdDisplay.Opacity = args.sd_products_opacity - proddisplay.sd_productspvdDisplay.SetScalarBarVisibility(y.renderView1, False) - calculator1_display.Opacity = args.calculator1_opacity - attdisplay.sd_attributespvdDisplay.Opacity = args.sd_attributes_opacity - y.renderView1.Update() - - -def get_layout(*, y): - """Set the layout for the render view.""" - pvs.SetViewProperties( - Background=setup.inverted_color, UseColorPaletteForBackground=0 - ) - pvs.Render(setup.renderView1) - layout1 = pvs.GetLayout() - layout1.SetSize(args.animation_size) - layout1.PreviewMode = args.animation_size - y.renderView1.Update() - - -def set_current_camera_placement(*, y): - """Set the camera placement for the render view.""" - y.renderView1.InteractionMode = "2D" - y.renderView1.CameraPosition = [836, 677, -4098] - y.renderView1.CameraFocalPoint = [636, 1030, 0.0] - y.renderView1.CameraViewUp = [1.0, 0.0, 0.0] - y.renderView1.CameraParallelScale = 1560 - y.renderView1.Update() - - -def axes_settings(*, view): - """Configure axes settings for the render view.""" - view.CenterAxesVisibility = True - view.OrientationAxesVisibility = False - axes_grid = view.AxesGrid - axes_grid.Visibility = True - axes_grid.XTitle = "Z [m]" - axes_grid.YTitle = "X [m]" - - axes_grid.XAxisUseCustomLabels = True - axes_grid.XAxisLabels = [300, 600, 900, 1200] - axes_grid.YAxisUseCustomLabels = True - axes_grid.YAxisLabels = [300, 600, 900, 1200] - - axes_grid.XTitleFontSize = 30 - axes_grid.XLabelFontSize = 30 - axes_grid.YTitleFontSize = 30 - axes_grid.YLabelFontSize = 30 - - axes_grid.XTitleColor = setup.color - axes_grid.XLabelColor = setup.color - axes_grid.YTitleColor = setup.color - axes_grid.YLabelColor = setup.color - axes_grid.GridColor = [0.1, 0.1, 0.1] - view.CenterAxesVisibility = False - view.Update() - - -def time_annotation(*, y): - """Add a time annotation to the render view.""" - time = pvs.AnnotateTimeFilter( - guiName="AnnotateTimeFilter1", Scale=1 / 60, Format="Time:{time:g}min" - ) - timedisplay = pvs.Show(time, y.renderView1) - timedisplay.FontSize = 25 - timedisplay.WindowLocation = "Any Location" - timedisplay.FontSize = 30 - timedisplay.Position = [0.4, 0.9] - timedisplay.Color = setup.color - y.renderView1.Update() - - -def text(text_in, position_y, *, view): - """Display text in the render view at a specified position.""" - sentence = pvs.Text() - sentence.Text = text_in - text_display = pvs.Show(sentence, view) - text_display.Color = setup.color - text_display.WindowLocation = "Any Location" - text_display.FontSize = 28 - text_display.Position = [0.17, position_y] - - -def last_anim_frame(animation_frame_name): - """Export the last animation frame to a file.""" - time_steps = sd_productspvd.TimestepValues - last_time = time_steps[90] - setup.renderView1.ViewTime = last_time - for reader in (sd_productspvd,): - reader.UpdatePipeline(last_time) - pvs.ExportView( - filename=str(pathlib.Path(args.output_path) / animation_frame_name), - view=setup.renderView1, - Rasterize3Dgeometry=False, - GL2PSdepthsortmethod="BSP sorting (slow, best)", - ) - pvs.RenderAllViews() - - -calculator1 = create_new_calculator( - { - "calcinput": sd_attributespvd, - "representation": "UnstructuredGridRepresentation", - "function": '"relative fall velocity"*(-iHat)', - "color_by1": "None", - "color_by2": "None", - "color_by3": "None", - "scalar_coloring": False, - "hide": False, - "setup_context": setup, - "registration_name": "Calculator1", - } -) - -create_glyph( - { - "registration_name": "Glyph1", - "put": calculator1, - "scale_array1": "POINTS", - "scale_array2": "relative fall velocity", - "color_by": False, - "setup_context": setup, - } -) - -apply_presets_logscale_opacity_and_update( - y=setup, attdisplay=setup, erLUT=setup, proddisplay=setup -) -get_layout(y=setup) -set_current_camera_placement(y=setup) -axes_settings(view=setup.renderView1) -time_annotation(y=setup) -if args.animationframename is not None: - last_anim_frame(animation_frame_name=args.animationframename) -scene = pvs.GetAnimationScene() -scene.UpdateAnimationUsingDataTimeSteps() -pvs.Render(setup.renderView1) -pvs.SaveAnimation( - str(pathlib.Path(args.output_path) / args.animationname), - setup.renderView1, - FrameRate=args.framerate, -) -pvs.RenderAllViews() diff --git a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py b/examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py deleted file mode 100644 index 73e2ff84c..000000000 --- a/examples/PySDM_examples/Strzabala_engineering_thesis_2025/no_glyphs.py +++ /dev/null @@ -1,362 +0,0 @@ -#!/usr/bin/env pvpython -"""Paraview rendering script. - -This module prepares Paraview scene, calculators, glyphs and exports animation/images. -Lint fixes: module docstring, protected-access disabled inline, reduced function args, -and short docstrings added to public functions. -""" -import argparse -from collections import namedtuple -import pathlib - -from paraview import simple as pvs # pylint: disable=import-error - -pvs._DisableFirstRenderCameraReset() # pylint: disable=protected-access - - -def cli_using_argparse(argp): - """Add and document command-line arguments used by this pvpython script. - - Parameters - ---------- - argp : argparse.ArgumentParser - ArgumentParser instance to which this function will add arguments. - """ - argp.add_argument("product_path", help="path to pvd products file") - argp.add_argument("attributes_path", help=" path to pvd attributes file") - argp.add_argument("output_path", help="path where to write output files") - argp.add_argument( - "--mode", - choices=["light", "dark"], - default="light", - help="Choose 'light' or 'dark' mode.", - ) - argp.add_argument( - "--multiplicity_preset", - default="Inferno (matplotlib)", - help="Preset for multiplicity", - ) - argp.add_argument( - "--multiplicity_logscale", - action="store_false", - help="Use log scale for multiplicity", - ) - argp.add_argument( - "--effectiveradius_preset", - default="Black, Blue and White", - help="Preset for effectiveradius", - ) - argp.add_argument( - "--effectiveradius_logscale", - action="store_false", - help="Use log scale for effectiveradius", - ) - argp.add_argument( - "--effectiveradius_nan_color", - nargs=3, - type=float, - default=[0.666, 0.333, 1.0], - help="Nan color in RGB format for effectiveradius", - ) - argp.add_argument( - "--sd_products_opacity", type=float, default=0.9, help="Opacity for sd_products" - ) - argp.add_argument( - "--calculator1_opacity", - type=float, - default=0.19, - help="Opacity for calculator1", - ) - argp.add_argument( - "--sd_attributes_opacity", - type=float, - default=0.77, - help="Opacity for sd_attributes", - ) - argp.add_argument( - "--animation_size", - nargs=2, - type=int, - default=[800, 800], - help="Animation size [x,y]", - ) - argp.add_argument( - "--animationframename", - type=str, - help="Name of the file with animation last frame", - ) - argp.add_argument( - "--animationname", - type=str, - help="Name of the file with animation", - ) - argp.add_argument( - "--framerate", type=int, help="Number of frame rates.", default=15 - ) - - -ap = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) -cli_using_argparse(ap) - -args = ap.parse_args() -sd_productspvd = pvs.OpenDataFile(args.product_path) -sd_attributespvd = pvs.OpenDataFile(args.attributes_path) - - -setup = { - "renderView1": pvs.GetActiveViewOrCreate("RenderView"), - "sd_attributespvdDisplay": pvs.GetDisplayProperties( - sd_attributespvd, view=pvs.GetActiveViewOrCreate("RenderView") - ), - "effectiveradiusLUT": pvs.GetColorTransferFunction("effectiveradius"), - "sd_productspvdDisplay": pvs.GetDisplayProperties( - sd_productspvd, view=pvs.GetActiveViewOrCreate("RenderView") - ), - "color": [1, 1, 1] if args.mode == "dark" else [0, 0, 0], - "inverted_color": [0.129, 0.145, 0.161] if args.mode == "dark" else [1, 1, 1], -} - -setup = namedtuple("Setup", setup.keys())(**setup) - -setup.effectiveradiusLUT.RescaleTransferFunction(0.1380997175392798, 207.7063518856934) -materialLibrary1 = pvs.GetMaterialLibrary() -setup.renderView1.Update() - - -def create_new_calculator( - calcinput, - representation, - function, - color_by, - *, - scalar_coloring=False, - hide=False, - y, - registration_name, -): - """Create and show a Calculator filter; return the calculator object. - - color_by should be a tuple (arrayName, association, component) or None. - """ - calculator = pvs.Calculator(registrationName=registration_name, Input=calcinput) - display = pvs.Show(calculator, y.renderView1, representation) - calculator.Function = function - y.renderView1.Update() - if scalar_coloring and color_by: - pvs.ColorBy(display, tuple(color_by)) - if hide: - pvs.Hide(calculator, y.renderView1) - return calculator - - -def scalar_bar(name, *, y, erLUT, calculator): - """Ensure scalar bar for given calculator is visible and styled.""" - calculator_display = pvs.Show( - calculator, y.renderView1, "UnstructuredGridRepresentation" - ) - calculator_display.SetScalarBarVisibility(y.renderView1, True) - scalar_bar_obj = pvs.GetScalarBar(erLUT.effectiveradiusLUT, y.renderView1) - scalar_bar_obj.ComponentTitle = "" - scalar_bar_obj.Title = name - scalar_bar_obj.TitleFontSize = 25 - scalar_bar_obj.LabelFontSize = 25 - scalar_bar_obj.LabelColor = setup.color - scalar_bar_obj.TitleColor = setup.color - y.renderView1.Update() - - -def create_glyph( - registration_name, put, scale_array1, scale_array2, color_by=False, *, y -): - """Create a glyph and return it.""" - glyph = pvs.Glyph(registrationName=registration_name, Input=put, GlyphType="Arrow") - glyph_display = pvs.Show(glyph, y.renderView1, "GeometryRepresentation") - glyph_display.Representation = "Surface" - glyph.ScaleArray = [scale_array1, scale_array2] - glyph.ScaleFactor = 100 - glyph_display.SetScalarBarVisibility(y.renderView1, True) - multiplicity_lut = pvs.GetColorTransferFunction("multiplicity") - multiplicity_lut_color_bar = pvs.GetScalarBar(multiplicity_lut, y.renderView1) - multiplicity_lut_color_bar.TitleFontSize = 25 - multiplicity_lut_color_bar.LabelFontSize = 25 - multiplicity_lut_color_bar.LabelColor = setup.color - multiplicity_lut_color_bar.TitleColor = setup.color - if color_by: - glyph_display.ColorArrayName = ["POINTS", ""] - pvs.ColorBy(glyph_display, None) - y.renderView1.Update() - return glyph - - -def apply_presets_logscale_opacity_and_update(*, y, attdisplay, erLUT, proddisplay): - """Apply LUT presets / logscale and set object opacities.""" - multiplicity_lut = pvs.GetColorTransferFunction("multiplicity") - multiplicity_lut.RescaleTransferFunction(19951.0, 50461190157.0) - calculator_1_display = pvs.Show( - calculator_1, y.renderView1, "UnstructuredGridRepresentation" - ) - multiplicity_lut.ApplyPreset(args.multiplicity_preset, True) - if args.multiplicity_logscale: - multiplicity_lut.MapControlPointsToLogSpace() - multiplicity_lut.UseLogScale = 1 - else: - multiplicity_lut.MapControlPointsToLinearSpace() - multiplicity_lut.UseLogScale = 0 - - erLUT.effectiveradiusLUT.ApplyPreset(args.effectiveradius_preset, True) - if args.effectiveradius_logscale: - erLUT.effectiveradiusLUT.MapControlPointsToLogSpace() - erLUT.effectiveradiusLUT.UseLogScale = 1 - else: - erLUT.effectiveradiusLUT.MapControlPointsToLinearSpace() - erLUT.effectiveradiusLUT.UseLogScale = 0 - - erLUT.effectiveradiusLUT.NanColor = args.effectiveradius_nan_color - - proddisplay.sd_productspvdDisplay.SetRepresentationType("Surface With Edges") - proddisplay.sd_productspvdDisplay.Opacity = args.sd_products_opacity - calculator_1_display.Opacity = args.calculator1_opacity - attdisplay.sd_attributespvdDisplay.Opacity = args.sd_attributes_opacity - - y.renderView1.Update() - - -def get_layout(*, y): - """Configure layout size for animation rendering.""" - pvs.SetViewProperties( - Background=setup.inverted_color, UseColorPaletteForBackground=0 - ) - pvs.Render(setup.renderView1) - layout1 = pvs.GetLayout() - layout1.SetSize(args.animation_size) - layout1.PreviewMode = args.animation_size - y.renderView1.Update() - - -def set_current_camera_placement(*, y): - """Set camera placement for the scene.""" - y.renderView1.InteractionMode = "2D" - y.renderView1.CameraPosition = [ - 836, - 677, - -4098, - ] - y.renderView1.CameraFocalPoint = [636, 1030, 0.0] - y.renderView1.CameraViewUp = [1.0, 0.0, 0.0] - y.renderView1.CameraParallelScale = 1560 - y.renderView1.Update() - - -def axes_settings(*, view): - """Configure axes grid, labels and styling on given view.""" - # setup.renderView1.Background = [1,0.5,0.2] - view.CenterAxesVisibility = True - view.OrientationAxesVisibility = False - axes_grid = view.AxesGrid - axes_grid.Visibility = True - axes_grid.XTitle = "Z [m]" - axes_grid.YTitle = "X [m]" - - axes_grid.XAxisUseCustomLabels = True - axes_grid.XAxisLabels = [300, 600, 900, 1200] - axes_grid.YAxisUseCustomLabels = True - axes_grid.YAxisLabels = [300, 600, 900, 1200] - - axes_grid.XTitleFontSize = 30 - axes_grid.XLabelFontSize = 30 - axes_grid.YTitleFontSize = 30 - axes_grid.YLabelFontSize = 30 - - axes_grid.XTitleColor = setup.color - axes_grid.XLabelColor = setup.color - axes_grid.YTitleColor = setup.color - axes_grid.YLabelColor = setup.color - axes_grid.GridColor = [0.1, 0.1, 0.1] - view.CenterAxesVisibility = False - view.Update() - - -def time_annotation(*, y): - """Add time annotation to the view.""" - time = pvs.AnnotateTimeFilter( - guiName="AnnotateTimeFilter1", Scale=1 / 60, Format="Time:{time:g}min" - ) - timedisplay = pvs.Show(time, y.renderView1) - timedisplay.FontSize = 25 - timedisplay.WindowLocation = "Any Location" - timedisplay.FontSize = 30 - timedisplay.Position = [0.4, 0.9] - timedisplay.Color = setup.color - y.renderView1.Update() - - -def text(text_in, position_y, *, view): - """Place a small text label on view (no return).""" - sentence = pvs.Text() - sentence.Text = text_in - text_display = pvs.Show(sentence, view) - text_display.Color = setup.color - text_display.WindowLocation = "Any Location" - text_display.FontSize = 28 - text_display.Position = [0.17, position_y] - - -def last_anim_frame(animation_frame_name): - """Export last animation frame to a file in output path.""" - time_steps = sd_productspvd.TimestepValues - last_time = time_steps[90] - setup.renderView1.ViewTime = last_time - for reader in (sd_productspvd,): - reader.UpdatePipeline(last_time) - pvs.ExportView( - filename=str(pathlib.Path(args.output_path) / animation_frame_name), - view=setup.renderView1, - Rasterize3Dgeometry=False, - GL2PSdepthsortmethod="BSP sorting (slow, best)", - ) - pvs.RenderAllViews() - - -calculator_1 = create_new_calculator( - sd_attributespvd, - "UnstructuredGridRepresentation", - '"relative fall velocity"*(-iHat)', - ("None", "None", "None"), - y=setup, - registration_name="Calculator1", -) -scalar_bar("effective radius [um]", y=setup, erLUT=setup, calculator=calculator_1) -glyph_1 = create_glyph( - "Glyph1", calculator_1, "POINTS", "relative fall velocity", y=setup -) -pvs.Hide(glyph_1) -calculator_2 = create_new_calculator( - sd_productspvd, - "StructuredGridRepresentation", - "cx*jHat+cy*iHat", - ("CELLS", "Result", "Magnitude"), - scalar_coloring=True, - hide=True, - y=setup, - registration_name="Calculator2", -) -apply_presets_logscale_opacity_and_update( - y=setup, attdisplay=setup, erLUT=setup, proddisplay=setup -) -glyph_2 = create_glyph("Glyph2", calculator_2, "CELLS", "Result", True, y=setup) -pvs.Hide(glyph_2) -get_layout(y=setup) -set_current_camera_placement(y=setup) -axes_settings(view=setup.renderView1) -time_annotation(y=setup) -if args.animationframename is not None: - last_anim_frame(animation_frame_name=args.animationframename) -scene = pvs.GetAnimationScene() -scene.UpdateAnimationUsingDataTimeSteps() -pvs.Render(setup.renderView1) -pvs.SaveAnimation( - str(pathlib.Path(args.output_path) / args.animationname), - setup.renderView1, - FrameRate=args.framerate, -) -pvs.RenderAllViews() diff --git a/examples/docs/pysdm_examples_landing.md b/examples/docs/pysdm_examples_landing.md index 00a5692ec..f5a810937 100644 --- a/examples/docs/pysdm_examples_landing.md +++ b/examples/docs/pysdm_examples_landing.md @@ -86,6 +86,7 @@ Example notebooks include: - `PySDM_examples.Yang_et_al_2018`: polydisperse particle spectrum, activation/deactivation cycles - `PySDM_examples.Abdul_Razzak_Ghan_2000`: polydisperse activation, comparison against GCM parameterisation - `PySDM_examples.Pyrcel`: polydisperse activation, mimicking example test case from Pyrcel documentation + - `PySDM_examples.Strzabala_2025_BEng`: ParaView visualisation example - `PySDM_examples.Lowe_et_al_2019`: externally mixed polydisperse size spectrum with surface-active organics case - `PySDM_examples.Grabowski_and_Pawlowska_2023`: polydisperse activation, focus on ripening - `PySDM_examples.Jensen_and_Nugent_2017`: polydisperse activation featuring giant CCN diff --git a/tests/unit_tests/exporters/test_parcel_vtk_exporter.py b/tests/unit_tests/exporters/test_parcel_vtk_exporter.py new file mode 100644 index 000000000..156f0b460 --- /dev/null +++ b/tests/unit_tests/exporters/test_parcel_vtk_exporter.py @@ -0,0 +1,205 @@ +"""Test module for VTKExporterPyrcel.""" + +from unittest.mock import Mock +import numpy as np +import pytest + +from PySDM.exporters.parcel_vtk_exporter import VTKExporterPyrcel + + +class TestVTKExporterPyrcel: + """Test class for VTKExporterPyrcel functionality.""" + + @staticmethod + @pytest.fixture + def mock_simulation(): + """Mock simulation object with necessary attributes.""" + simulation = Mock() + simulation.particulator = Mock() + simulation.particulator.dt = 1.0 + simulation.particulator.n_sd = 100 + simulation.particulator.environment = Mock() + simulation.particulator.environment.mass_of_dry_air = 66666 + + return simulation + + @staticmethod + @pytest.fixture + def mock_output(): + """Mock output data structure.""" + n_levels = 5 + output = { + "products": { + "z": np.linspace(0, 100, n_levels), + "rhod": np.ones(n_levels) * 1.2, + "S_max_percent": np.linspace(100, 110, n_levels), + }, + "attributes": { + "radius": np.random.random((100, 10)), + "n": np.random.random((100, 10)), + }, + } + return output + + def test_vtk_exporter_pyrcel_initialization(self, mock_output): + """Test that VTKExporterPyrcel initializes correctly.""" + # Arrange + n_sd = 100 + mass_of_dry_air = 66666 + + # Act + exporter = VTKExporterPyrcel(n_sd, mock_output, mass_of_dry_air) + + # Assert + assert exporter.output == mock_output + assert len(exporter.x_coords) == n_sd + assert len(exporter.y_coords) == n_sd + assert len(exporter.z_coords) == n_sd + assert len(exporter.half_diagonal) == exporter.n_levels + assert exporter.n_levels == len(mock_output["products"]["z"]) + + def test_vtk_exporter_pyrcel_export_products( + self, mock_output, mock_simulation, tmp_path + ): + """Test exporting products to VTK format.""" + # Arrange + n_sd = 100 + mass_of_dry_air = 66666 + + exporter = VTKExporterPyrcel(n_sd, mock_output, mass_of_dry_air) + exporter.path = str(tmp_path) + exporter.attributes_file_path = str(tmp_path / "sd_attributes") + exporter.products_file_path = str(tmp_path / "sd_products") + exporter.exported_times = {"products": {}, "attributes": {}} + + step = 1 + + # Act + exporter.export_products(step, mock_simulation) + + # Assert + expected_file = ( + tmp_path / f"sd_products_num{exporter.add_leading_zeros(step)}.vtu" + ) + assert expected_file.exists() + + assert len(exporter.exported_times["products"]) == 1 + expected_time = step * mock_simulation.particulator.dt + assert list(exporter.exported_times["products"].values())[0] == expected_time + + def test_vtk_exporter_pyrcel_export_attributes( + self, mock_output, mock_simulation, tmp_path + ): + """Test exporting attributes to VTK format.""" + # Arrange + n_sd = 100 + mass_of_dry_air = 66666 + + exporter = VTKExporterPyrcel(n_sd, mock_output, mass_of_dry_air) + exporter.path = str(tmp_path) + exporter.attributes_file_path = str(tmp_path / "sd_attributes") + exporter.products_file_path = str(tmp_path / "sd_products") + exporter.exported_times = {"products": {}, "attributes": {}} + + step = 1 + + # Act + exporter.export_attributes(step, mock_simulation) + + # Assert + expected_file = ( + tmp_path / f"sd_attributes_num{exporter.add_leading_zeros(step)}.vtu" + ) + assert expected_file.exists() + + assert len(exporter.exported_times["attributes"]) == 1 + expected_time = step * mock_simulation.particulator.dt + assert list(exporter.exported_times["attributes"].values())[0] == expected_time + + def test_vtk_exporter_pyrcel_write_pvd( + self, mock_output, mock_simulation, tmp_path + ): + """Test writing PVD collection files.""" + # Arrange + n_sd = 100 + mass_of_dry_air = 66666 + + exporter = VTKExporterPyrcel(n_sd, mock_output, mass_of_dry_air) + exporter.path = str(tmp_path) + exporter.attributes_file_path = str(tmp_path / "sd_attributes") + exporter.products_file_path = str(tmp_path / "sd_products") + exporter.exported_times = {"products": {}, "attributes": {}} + + steps = [1, 2] + for step in steps: + exporter.export_products(step, mock_simulation) + exporter.export_attributes(step, mock_simulation) + + # Act + exporter.write_pvd() + + # Assert + attributes_pvd = tmp_path / "sd_attributes.pvd" + products_pvd = tmp_path / "sd_products.pvd" + + assert attributes_pvd.exists() + assert products_pvd.exists() + + def test_vtk_exporter_pyrcel_coordinate_calculation( + self, mock_output, mock_simulation, tmp_path + ): + """Test that coordinate calculations work correctly across multiple steps.""" + # Arrange + exporter = VTKExporterPyrcel(100, mock_output, 666666) + exporter.path = str(tmp_path) + exporter.attributes_file_path = str(tmp_path / "sd_attributes") + exporter.products_file_path = str(tmp_path / "sd_products") + exporter.exported_times = {"products": {}, "attributes": {}} + + initial_z_coords = exporter.z_coords.copy() + + # Act + step1 = 1 + exporter.export_attributes(step1, mock_simulation) + z_after_step1 = exporter.z_coords.copy() + + # Act + step2 = 2 + exporter.export_attributes(step2, mock_simulation) + z_after_step2 = exporter.z_coords.copy() + + # Assert + if step1 != 0: + delta_z_step1 = ( + mock_output["products"]["z"][step1] + - mock_output["products"]["z"][step1 - 1] + ) + expected_z_step1 = initial_z_coords * delta_z_step1 + np.testing.assert_array_equal(z_after_step1, expected_z_step1) + + if step2 != 0: + delta_z_step2 = ( + mock_output["products"]["z"][step2] + - mock_output["products"]["z"][step2 - 1] + ) + expected_z_step2 = z_after_step1 + delta_z_step2 + np.testing.assert_array_equal(z_after_step2, expected_z_step2) + + def test_vtk_exporter_pyrcel_half_diagonal_calculation(self, mock_output): + """Test the half_diagonal calculation logic.""" + # Arrange + n_sd = 100 + mass_of_dry_air = 66666 + + # Act + exporter = VTKExporterPyrcel(n_sd, mock_output, mass_of_dry_air) + + # Assert + assert len(exporter.half_diagonal) == exporter.n_levels + assert all(hd > 0 for hd in exporter.half_diagonal) + + volume_0 = mass_of_dry_air / mock_output["products"]["rhod"][0] + delta_z_0 = mock_output["products"]["z"][1] - mock_output["products"]["z"][0] + area_0 = volume_0 / delta_z_0 + expected_hd_0 = (2 * area_0) ** 0.5 + assert abs(exporter.half_diagonal[0] - expected_hd_0) < 1e-10 From 6ea0d30bf77e50ebe23d9144e0a899f4b187c60a Mon Sep 17 00:00:00 2001 From: olastrz Date: Fri, 28 Nov 2025 12:13:03 +0100 Subject: [PATCH 23/29] Update to test names and getting rid of too many instance attributes --- PySDM/exporters/__init__.py | 1 + ...vtk_exporter.py => vtk_exporter_parcel.py} | 26 ++-- ...xporter.py => test_vtk_exporter_parcel.py} | 137 +++++++++--------- 3 files changed, 80 insertions(+), 84 deletions(-) rename PySDM/exporters/{parcel_vtk_exporter.py => vtk_exporter_parcel.py} (88%) rename tests/unit_tests/exporters/{test_parcel_vtk_exporter.py => test_vtk_exporter_parcel.py} (56%) diff --git a/PySDM/exporters/__init__.py b/PySDM/exporters/__init__.py index 6bb5a9c3a..7099e94d5 100644 --- a/PySDM/exporters/__init__.py +++ b/PySDM/exporters/__init__.py @@ -6,3 +6,4 @@ from .netcdf_exporter_1d import NetCDFExporter_1d, readNetCDF_1d from .vtk_exporter import VTKExporter from .vtk_exporter_1d import VTKExporter_1d +from .vtk_exporter_parcel import VTKExporterParcel diff --git a/PySDM/exporters/parcel_vtk_exporter.py b/PySDM/exporters/vtk_exporter_parcel.py similarity index 88% rename from PySDM/exporters/parcel_vtk_exporter.py rename to PySDM/exporters/vtk_exporter_parcel.py index 96557b45d..dec885e1d 100644 --- a/PySDM/exporters/parcel_vtk_exporter.py +++ b/PySDM/exporters/vtk_exporter_parcel.py @@ -1,7 +1,7 @@ """ -VTK Exporter for Pyrcel PySDM simulations. +VTK Exporter for parcel PySDM simulations. -This module defines `VTKExporterPyrcel`, a subclass of `PySDM.exporters.VTKExporter`, +This module defines `VTKExporterParcel`, a subclass of `PySDM.exporters.VTKExporter`, that writes simulation outputs to VTK format using `pyevtk`. It exports product profiles (e.g., relative humidity) as unstructured grids and particle attributes as point clouds, along with `.pvd` collection files for time-series visualization @@ -15,18 +15,20 @@ from PySDM.exporters import VTKExporter -class VTKExporterPyrcel(VTKExporter): +class VTKExporterParcel(VTKExporter): """ - Custom VTK exporter for Pyrcel PySDM, exporting products as grids + Custom VTK exporter for parcel PySDM, exporting products as grids and attributes as point clouds for ParaView visualization. """ def __init__(self, n_sd, output, mass_of_dry_air): super().__init__() self.output = output - self.x_coords = np.random.random(n_sd) - self.y_coords = np.random.random(n_sd) - self.z_coords = np.random.random(n_sd) + self.coords = { + "x": np.random.random(n_sd), + "y": np.random.random(n_sd), + "z": np.random.random(n_sd), + } self.half_diagonal = [] self.n_levels = len(self.output["products"]["z"]) @@ -135,14 +137,14 @@ def export_attributes(self, step, simulation): # pylint: disable=arguments-diff - self.output["products"]["z"][step - 1] ) if step == 1: - self.z_coords *= delta_z + self.coords["z"] *= delta_z else: - self.z_coords += delta_z + self.coords["z"] += delta_z pointsToVTK( path, - 2 * (self.x_coords - 0.5) * self.half_diagonal[step], - 2 * (self.y_coords - 0.5) * self.half_diagonal[step], - self.z_coords, + 2 * (self.coords["x"] - 0.5) * self.half_diagonal[step], + 2 * (self.coords["y"] - 0.5) * self.half_diagonal[step], + self.coords["z"], data=payload, ) diff --git a/tests/unit_tests/exporters/test_parcel_vtk_exporter.py b/tests/unit_tests/exporters/test_vtk_exporter_parcel.py similarity index 56% rename from tests/unit_tests/exporters/test_parcel_vtk_exporter.py rename to tests/unit_tests/exporters/test_vtk_exporter_parcel.py index 156f0b460..65c25cf95 100644 --- a/tests/unit_tests/exporters/test_parcel_vtk_exporter.py +++ b/tests/unit_tests/exporters/test_vtk_exporter_parcel.py @@ -1,14 +1,12 @@ -"""Test module for VTKExporterPyrcel.""" - +# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring from unittest.mock import Mock import numpy as np import pytest -from PySDM.exporters.parcel_vtk_exporter import VTKExporterPyrcel +from PySDM.exporters import VTKExporterParcel -class TestVTKExporterPyrcel: - """Test class for VTKExporterPyrcel functionality.""" +class TestParcelVTKExporter: @staticmethod @pytest.fixture @@ -41,32 +39,31 @@ def mock_output(): } return output - def test_vtk_exporter_pyrcel_initialization(self, mock_output): - """Test that VTKExporterPyrcel initializes correctly.""" + def test_initialization(self, mock_output, mock_simulation): # Arrange - n_sd = 100 - mass_of_dry_air = 66666 # Act - exporter = VTKExporterPyrcel(n_sd, mock_output, mass_of_dry_air) + exporter = VTKExporterParcel( + n_sd=mock_simulation.particulator.n_sd, + output=mock_output, + mass_of_dry_air=mock_simulation.particulator.environment.mass_of_dry_air, + ) # Assert assert exporter.output == mock_output - assert len(exporter.x_coords) == n_sd - assert len(exporter.y_coords) == n_sd - assert len(exporter.z_coords) == n_sd + assert len(exporter.coords["x"]) == mock_simulation.particulator.n_sd + assert len(exporter.coords["y"]) == mock_simulation.particulator.n_sd + assert len(exporter.coords["z"]) == mock_simulation.particulator.n_sd assert len(exporter.half_diagonal) == exporter.n_levels assert exporter.n_levels == len(mock_output["products"]["z"]) - def test_vtk_exporter_pyrcel_export_products( - self, mock_output, mock_simulation, tmp_path - ): - """Test exporting products to VTK format.""" + def test_export_products(self, mock_output, mock_simulation, tmp_path): # Arrange - n_sd = 100 - mass_of_dry_air = 66666 - - exporter = VTKExporterPyrcel(n_sd, mock_output, mass_of_dry_air) + exporter = VTKExporterParcel( + n_sd=mock_simulation.particulator.n_sd, + output=mock_output, + mass_of_dry_air=mock_simulation.particulator.environment.mass_of_dry_air, + ) exporter.path = str(tmp_path) exporter.attributes_file_path = str(tmp_path / "sd_attributes") exporter.products_file_path = str(tmp_path / "sd_products") @@ -87,15 +84,13 @@ def test_vtk_exporter_pyrcel_export_products( expected_time = step * mock_simulation.particulator.dt assert list(exporter.exported_times["products"].values())[0] == expected_time - def test_vtk_exporter_pyrcel_export_attributes( - self, mock_output, mock_simulation, tmp_path - ): - """Test exporting attributes to VTK format.""" + def test_export_attributes(self, mock_output, mock_simulation, tmp_path): # Arrange - n_sd = 100 - mass_of_dry_air = 66666 - - exporter = VTKExporterPyrcel(n_sd, mock_output, mass_of_dry_air) + exporter = VTKExporterParcel( + n_sd=mock_simulation.particulator.n_sd, + output=mock_output, + mass_of_dry_air=mock_simulation.particulator.environment.mass_of_dry_air, + ) exporter.path = str(tmp_path) exporter.attributes_file_path = str(tmp_path / "sd_attributes") exporter.products_file_path = str(tmp_path / "sd_products") @@ -116,15 +111,13 @@ def test_vtk_exporter_pyrcel_export_attributes( expected_time = step * mock_simulation.particulator.dt assert list(exporter.exported_times["attributes"].values())[0] == expected_time - def test_vtk_exporter_pyrcel_write_pvd( - self, mock_output, mock_simulation, tmp_path - ): - """Test writing PVD collection files.""" + def test_write_pvd(self, mock_output, mock_simulation, tmp_path): # Arrange - n_sd = 100 - mass_of_dry_air = 66666 - - exporter = VTKExporterPyrcel(n_sd, mock_output, mass_of_dry_air) + exporter = VTKExporterParcel( + n_sd=mock_simulation.particulator.n_sd, + output=mock_output, + mass_of_dry_air=mock_simulation.particulator.environment.mass_of_dry_air, + ) exporter.path = str(tmp_path) exporter.attributes_file_path = str(tmp_path / "sd_attributes") exporter.products_file_path = str(tmp_path / "sd_products") @@ -145,60 +138,60 @@ def test_vtk_exporter_pyrcel_write_pvd( assert attributes_pvd.exists() assert products_pvd.exists() - def test_vtk_exporter_pyrcel_coordinate_calculation( - self, mock_output, mock_simulation, tmp_path - ): - """Test that coordinate calculations work correctly across multiple steps.""" + def test_coordinate_calculation(self, mock_output, mock_simulation, tmp_path): # Arrange - exporter = VTKExporterPyrcel(100, mock_output, 666666) + exporter = VTKExporterParcel( + n_sd=mock_simulation.particulator.n_sd, + output=mock_output, + mass_of_dry_air=mock_simulation.particulator.environment.mass_of_dry_air, + ) exporter.path = str(tmp_path) exporter.attributes_file_path = str(tmp_path / "sd_attributes") exporter.products_file_path = str(tmp_path / "sd_products") exporter.exported_times = {"products": {}, "attributes": {}} - initial_z_coords = exporter.z_coords.copy() + initial_z_coords = exporter.coords["z"].copy() # Act - step1 = 1 - exporter.export_attributes(step1, mock_simulation) - z_after_step1 = exporter.z_coords.copy() + exporter.export_attributes(step=(step1 := 1), simulation=mock_simulation) + z_after_step1 = exporter.coords["z"].copy() - # Act - step2 = 2 - exporter.export_attributes(step2, mock_simulation) - z_after_step2 = exporter.z_coords.copy() + exporter.export_attributes(step=(step2 := 2), simulation=mock_simulation) + z_after_step2 = exporter.coords["z"].copy() # Assert - if step1 != 0: - delta_z_step1 = ( - mock_output["products"]["z"][step1] - - mock_output["products"]["z"][step1 - 1] - ) - expected_z_step1 = initial_z_coords * delta_z_step1 - np.testing.assert_array_equal(z_after_step1, expected_z_step1) - - if step2 != 0: - delta_z_step2 = ( - mock_output["products"]["z"][step2] - - mock_output["products"]["z"][step2 - 1] - ) - expected_z_step2 = z_after_step1 + delta_z_step2 - np.testing.assert_array_equal(z_after_step2, expected_z_step2) - - def test_vtk_exporter_pyrcel_half_diagonal_calculation(self, mock_output): - """Test the half_diagonal calculation logic.""" + delta_z_step1 = ( + mock_output["products"]["z"][step1] + - mock_output["products"]["z"][step1 - 1] + ) + expected_z_step1 = initial_z_coords * delta_z_step1 + np.testing.assert_array_equal(z_after_step1, expected_z_step1) + + delta_z_step2 = ( + mock_output["products"]["z"][step2] + - mock_output["products"]["z"][step2 - 1] + ) + expected_z_step2 = z_after_step1 + delta_z_step2 + np.testing.assert_array_equal(z_after_step2, expected_z_step2) + + def test_half_diagonal_calculation(self, mock_output, mock_simulation): # Arrange - n_sd = 100 - mass_of_dry_air = 66666 # Act - exporter = VTKExporterPyrcel(n_sd, mock_output, mass_of_dry_air) + exporter = VTKExporterParcel( + n_sd=mock_simulation.particulator.n_sd, + output=mock_output, + mass_of_dry_air=mock_simulation.particulator.environment.mass_of_dry_air, + ) # Assert assert len(exporter.half_diagonal) == exporter.n_levels assert all(hd > 0 for hd in exporter.half_diagonal) - volume_0 = mass_of_dry_air / mock_output["products"]["rhod"][0] + volume_0 = ( + mock_simulation.particulator.environment.mass_of_dry_air + / mock_output["products"]["rhod"][0] + ) delta_z_0 = mock_output["products"]["z"][1] - mock_output["products"]["z"][0] area_0 = volume_0 / delta_z_0 expected_hd_0 = (2 * area_0) ** 0.5 From b63ee7d22ba74a2f2ef78cdc962008ba8aff0055 Mon Sep 17 00:00:00 2001 From: olastrz Date: Fri, 28 Nov 2025 13:37:43 +0100 Subject: [PATCH 24/29] Fix cyclic import issue --- PySDM/exporters/vtk_exporter_parcel.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PySDM/exporters/vtk_exporter_parcel.py b/PySDM/exporters/vtk_exporter_parcel.py index dec885e1d..b90766f8b 100644 --- a/PySDM/exporters/vtk_exporter_parcel.py +++ b/PySDM/exporters/vtk_exporter_parcel.py @@ -12,7 +12,7 @@ from pyevtk.vtk import VtkHexahedron, VtkGroup import numpy as np -from PySDM.exporters import VTKExporter +from PySDM.exporters.vtk_exporter import VTKExporter class VTKExporterParcel(VTKExporter): @@ -21,7 +21,9 @@ class VTKExporterParcel(VTKExporter): and attributes as point clouds for ParaView visualization. """ - def __init__(self, n_sd, output, mass_of_dry_air): + def __init__( + self, n_sd, output, mass_of_dry_air + ): # pylint: disable=too-many-instance-attributes super().__init__() self.output = output self.coords = { From 368fd4e0f943df35d1e34b44b13fe36aa1d28c42 Mon Sep 17 00:00:00 2001 From: olastrz Date: Fri, 28 Nov 2025 13:44:24 +0100 Subject: [PATCH 25/29] Docs update and pylint disable --- PySDM/exporters/vtk_exporter_parcel.py | 5 ++--- examples/PySDM_examples/Strzabala_2025_BEng/__init__.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/PySDM/exporters/vtk_exporter_parcel.py b/PySDM/exporters/vtk_exporter_parcel.py index b90766f8b..b137ba529 100644 --- a/PySDM/exporters/vtk_exporter_parcel.py +++ b/PySDM/exporters/vtk_exporter_parcel.py @@ -15,15 +15,14 @@ from PySDM.exporters.vtk_exporter import VTKExporter +# pylint: disable=too-many-instance-attributes class VTKExporterParcel(VTKExporter): """ Custom VTK exporter for parcel PySDM, exporting products as grids and attributes as point clouds for ParaView visualization. """ - def __init__( - self, n_sd, output, mass_of_dry_air - ): # pylint: disable=too-many-instance-attributes + def __init__(self, n_sd, output, mass_of_dry_air): super().__init__() self.output = output self.coords = { diff --git a/examples/PySDM_examples/Strzabala_2025_BEng/__init__.py b/examples/PySDM_examples/Strzabala_2025_BEng/__init__.py index 224822c35..168e50fdb 100644 --- a/examples/PySDM_examples/Strzabala_2025_BEng/__init__.py +++ b/examples/PySDM_examples/Strzabala_2025_BEng/__init__.py @@ -4,5 +4,5 @@ [Pyrcel package docs](https://pyrcel.readthedocs.io/) paraview_parcel_model.ipynb: -.. include:: ./paraview_parcel_model.ipynb.badges.md +.. include:: ./paraview.ipynb.badges.md """ From 60e70c6fb1f77135c29922213342f40ac2c1f882 Mon Sep 17 00:00:00 2001 From: olastrz Date: Fri, 28 Nov 2025 14:02:42 +0100 Subject: [PATCH 26/29] Adding badges and description to notebook --- .../Strzabala_2025_BEng/paraview.ipynb | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb b/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb index 2ec8f17e0..187ddfdaf 100644 --- a/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb +++ b/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb @@ -1,14 +1,46 @@ { "cells": [ + { + "cell_type": "markdown", + "id": "ea16d42c", + "metadata": {}, + "source": [ + "[![preview notebook](https://img.shields.io/static/v1?label=render%20on&logo=github&color=87ce3e&message=GitHub)](https://github.com/open-atmos/PySDM/blob/main/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb)\n", + "[![launch on mybinder.org](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/open-atmos/PySDM.git/main?urlpath=lab/tree/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb)\n", + "[![launch on Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/open-atmos/PySDM/blob/main/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb)" + ] + }, + { + "cell_type": "markdown", + "id": "bdde4d45", + "metadata": {}, + "source": [ + "Runs a parcel simulation based on Pyrcel documentation setup, and demonstrates export to VTK and visualisation using Paraview\n", + "\n", + "(requires `pvpython` command in PATH)" + ] + }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, + "id": "1829d6ee", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "if 'google.colab' in sys.modules:\n", + " !pip --quiet install open-atmos-jupyter-utils\n", + " from open_atmos_jupyter_utils import pip_install_on_colab\n", + " pip_install_on_colab('PySDM-examples')" + ] + }, + { + "cell_type": "code", + "execution_count": null, "id": "6dcbcc6d", "metadata": {}, "outputs": [], "source": [ - "\"\"\"Run Pyrcel simulation and export Paraview files.\"\"\"\n", - "\n", "import numpy as np\n", "import subprocess\n", "import platform\n", @@ -27,7 +59,7 @@ "\n", "from PySDM_examples.Pyrcel import Settings, Simulation\n", "\n", - "from PySDM.exporters.parcel_vtk_exporter import VTKExporterPyrcel" + "from PySDM.exporters import VTKExporterPyrcel" ] }, { From d2f35cf0e0d16e38d1a7f576739c3eae6ba5f964 Mon Sep 17 00:00:00 2001 From: Sylwester Arabas Date: Fri, 28 Nov 2025 16:12:31 +0100 Subject: [PATCH 27/29] Add 'Strzabala_2025_BEng' to example-test list --- tests/examples_tests/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/examples_tests/conftest.py b/tests/examples_tests/conftest.py index 98b618ee5..732788974 100644 --- a/tests/examples_tests/conftest.py +++ b/tests/examples_tests/conftest.py @@ -139,6 +139,7 @@ def findfiles(path, regex): "multi-process_a": [ "Arabas_et_al_2015", "_HOWTOs", + "Strzabala_2025_BEng", ], "multi-process_b": [ "Arabas_et_al_2025", From 33f1153c6491396592a6e56f40884f2bbe5468c1 Mon Sep 17 00:00:00 2001 From: Sylwester Arabas Date: Sat, 29 Nov 2025 00:39:45 +0100 Subject: [PATCH 28/29] Replace VTKExporterPyrcel with VTKExporterParcel --- examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb b/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb index 187ddfdaf..0e43f3537 100644 --- a/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb +++ b/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb @@ -59,7 +59,7 @@ "\n", "from PySDM_examples.Pyrcel import Settings, Simulation\n", "\n", - "from PySDM.exporters import VTKExporterPyrcel" + "from PySDM.exporters import VTKExporterParcel" ] }, { @@ -131,7 +131,7 @@ "metadata": {}, "outputs": [], "source": [ - "e = VTKExporterPyrcel(n_sd=simulation.particulator.n_sd, output=output, mass_of_dry_air=simulation.particulator.environment.mass_of_dry_air)\n", + "e = VTKExporterParcel(n_sd=simulation.particulator.n_sd, output=output, mass_of_dry_air=simulation.particulator.environment.mass_of_dry_air)\n", "for step in settings.output_steps:\n", " e.export_products(step, simulation)\n", " e.export_attributes(step, simulation)\n", From 125edbed215b84e6efacba5e4fae3b371bdec183 Mon Sep 17 00:00:00 2001 From: Sylwester Arabas Date: Sat, 29 Nov 2025 12:36:35 +0100 Subject: [PATCH 29/29] correct script path? --- .../Strzabala_2025_BEng/paraview.ipynb | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb b/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb index 0e43f3537..2537b940a 100644 --- a/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb +++ b/examples/PySDM_examples/Strzabala_2025_BEng/paraview.ipynb @@ -22,7 +22,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "1829d6ee", "metadata": {}, "outputs": [], @@ -36,7 +36,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "6dcbcc6d", "metadata": {}, "outputs": [], @@ -56,15 +56,15 @@ " ParticleSizeSpectrumPerVolume,\n", " ParticleVolumeVersusRadiusLogarithmSpectrum,\n", ")\n", + "from PySDM.exporters import VTKExporterParcel\n", "\n", "from PySDM_examples.Pyrcel import Settings, Simulation\n", - "\n", - "from PySDM.exporters import VTKExporterParcel" + "import PySDM_examples" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "cd6288b5", "metadata": {}, "outputs": [], @@ -116,7 +116,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "3ff50a25", "metadata": {}, "outputs": [], @@ -126,7 +126,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "15d59657", "metadata": {}, "outputs": [], @@ -140,7 +140,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "4a6ea0e6", "metadata": {}, "outputs": [], @@ -148,7 +148,7 @@ "product = pathlib.Path(\"./output/sd_products.pvd\").absolute()\n", "attributes = pathlib.Path(\"./output/sd_attributes.pvd\").absolute()\n", "\n", - "paraview_script = pathlib.Path(\"./paraview_parcel_model.py\").absolute()\n", + "paraview_script = pathlib.Path(PySDM_examples.__file__).parent / 'Strzabala_2025_BEng' / \"paraview_parcel_model.py\"\n", "\n", "args = [\n", " \"pvpython\",\n", @@ -170,11 +170,35 @@ " text=True,\n", ")" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e65c734-7012-4eff-8099-daa1119cb97d", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "baea1aff-648f-41c0-b97b-4bf8f0b6de31", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2d64ba1c-5eb9-4141-90a9-5a3da6ad7a71", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "base", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -188,7 +212,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.9.2" } }, "nbformat": 4,