|
335 | 335 | "$ u = \\sum_{j=1}^N U_j\\phi_j.$\n",
|
336 | 336 | "By writing `problem.solve()` we compute all the coefficients $U_1,\\dots, U_N$. These values are known as the _degrees of freedom_ (dofs). We can access the degrees of freedom by accessing the underlying vector in `uh`.\n",
|
337 | 337 | "However, as a second order function space has more dofs than a linear function space, we cannot compare these arrays directly.\n",
|
338 |
| - "Therefore we compute the values of both `uex` and `uD` at the mesh nodes (for a linear mesh this is the vertices)." |
| 338 | + "As we allready have interpolated the exact solution into the first order space when creating the boundary condition, we can compare the maximum values at any degree of freedom of the approximation space." |
339 | 339 | ]
|
340 | 340 | },
|
341 | 341 | {
|
|
353 | 353 | }
|
354 | 354 | ],
|
355 | 355 | "source": [
|
356 |
| - "u_vertex_values = uh.compute_point_values()\n", |
357 |
| - "u_ex_vertex_values = uex.compute_point_values()\n", |
358 |
| - "error_max = numpy.max(numpy.abs(u_vertex_values - u_ex_vertex_values))\n", |
| 356 | + "error_max = numpy.max(numpy.abs(uD.x.array-uh.x.array))\n", |
359 | 357 | "# Only print the error on one process\n",
|
360 | 358 | "if mesh.comm.rank == 0:\n",
|
361 | 359 | " print(f\"Error_L2 : {error_L2:.2e}\")\n",
|
|
366 | 364 | "cell_type": "markdown",
|
367 | 365 | "metadata": {},
|
368 | 366 | "source": [
|
369 |
| - "## Plotting the solution using pyvista\n", |
370 |
| - "Once the solution has been computed, we will visualize it using [pyvista](https://docs.pyvista.org/), an interface to the VTK toolkit.\n", |
| 367 | + "## Plotting the mesh using pyvista\n", |
| 368 | + "We will visualizing the mesh using [pyvista](https://docs.pyvista.org/), an interface to the VTK toolkit.\n", |
371 | 369 | "We start by converting the mesh to a format that can be used with `pyvista`.\n",
|
372 |
| - "To do this we use the function `dolfinx.plot.create_vtk_topology`. The first step is to create an unstructured grid that can be used by `pyvista`." |
| 370 | + "To do this we use the function `dolfinx.plot.create_vtk_mesh`. The first step is to create an unstructured grid that can be used by `pyvista`." |
373 | 371 | ]
|
374 | 372 | },
|
375 | 373 | {
|
|
378 | 376 | "metadata": {},
|
379 | 377 | "outputs": [],
|
380 | 378 | "source": [
|
381 |
| - "from dolfinx.plot import create_vtk_topology\n", |
382 |
| - "topology, cell_types = create_vtk_topology(mesh, mesh.topology.dim)" |
| 379 | + "from dolfinx.plot import create_vtk_mesh\n", |
| 380 | + "import pyvista\n", |
| 381 | + "topology, cell_types, geometry = create_vtk_mesh(mesh, mesh.topology.dim)\n", |
| 382 | + "grid = pyvista.UnstructuredGrid(topology, cell_types, geometry)" |
383 | 383 | ]
|
384 | 384 | },
|
385 | 385 | {
|
|
395 | 395 | "metadata": {},
|
396 | 396 | "outputs": [],
|
397 | 397 | "source": [
|
398 |
| - "import pyvista\n", |
399 | 398 | "pyvista.set_jupyter_backend(\"pythreejs\")"
|
400 | 399 | ]
|
401 | 400 | },
|
402 | 401 | {
|
403 | 402 | "cell_type": "markdown",
|
404 | 403 | "metadata": {},
|
405 | 404 | "source": [
|
406 |
| - "We start by creating a pyvista grid the `vtk_topology` and the `mesh.geometry`.\n", |
407 |
| - "Next, we attach data from our solution `uh` by computing the values of the function at each vertex." |
| 405 | + "We can now use the `pyvista.Plotter` to visualize the mesh. We visualize it by showing it in 2D and warped in 3D.\n", |
| 406 | + "In the jupyter notebook environment, we use the default setting of `pyvista.OFF_SCREEN=False`, which will render plots directly in the notebook." |
408 | 407 | ]
|
409 | 408 | },
|
410 | 409 | {
|
411 | 410 | "cell_type": "code",
|
412 | 411 | "execution_count": 15,
|
413 | 412 | "metadata": {},
|
414 |
| - "outputs": [], |
| 413 | + "outputs": [ |
| 414 | + { |
| 415 | + "data": { |
| 416 | + "application/vnd.jupyter.widget-view+json": { |
| 417 | + "model_id": "8153fbfcef014a3899925003792a4ba1", |
| 418 | + "version_major": 2, |
| 419 | + "version_minor": 0 |
| 420 | + }, |
| 421 | + "text/plain": [ |
| 422 | + "Renderer(camera=PerspectiveCamera(aspect=1.3333333333333333, children=(DirectionalLight(color='#fefefe', inten…" |
| 423 | + ] |
| 424 | + }, |
| 425 | + "metadata": {}, |
| 426 | + "output_type": "display_data" |
| 427 | + } |
| 428 | + ], |
415 | 429 | "source": [
|
416 |
| - "grid = pyvista.UnstructuredGrid(topology, cell_types, mesh.geometry.x)\n", |
417 |
| - "grid.point_data[\"u\"] = uh.compute_point_values().real\n", |
418 |
| - "grid.set_active_scalars(\"u\")" |
| 430 | + "plotter = pyvista.Plotter()\n", |
| 431 | + "plotter.add_mesh(grid, show_edges=True)\n", |
| 432 | + "plotter.view_xy()\n", |
| 433 | + "if not pyvista.OFF_SCREEN:\n", |
| 434 | + " plotter.show()\n", |
| 435 | + "else:\n", |
| 436 | + " pyvista.start_xvfb()\n", |
| 437 | + " figure = plotter.screenshot(\"fundamentals_mesh.png\")" |
419 | 438 | ]
|
420 | 439 | },
|
421 | 440 | {
|
422 | 441 | "cell_type": "markdown",
|
423 | 442 | "metadata": {},
|
424 | 443 | "source": [
|
425 |
| - "We can now use the `pyvista.Plotter` to visualize the solution. We visualize it by showing it in 2D and warped in 3D.\n", |
426 |
| - "In the jupyter notebook environment, we use the default setting of `pyvista.OFF_SCREEN=False`, which will render plots directly in the notebook." |
| 444 | + "## Plotting a function using pyvista\n", |
| 445 | + "We want to plot the solution `uh`. As the function space used to defined the mesh is disconnected from the function space defining the mesh, we create a mesh based on the dof coordinates for the function space `V`. We use `dolfinx.plot.create_vtk_mesh` with the function space as input to create a mesh with mesh geometry based on the dof coordinates." |
427 | 446 | ]
|
428 | 447 | },
|
429 | 448 | {
|
430 | 449 | "cell_type": "code",
|
431 | 450 | "execution_count": 16,
|
432 | 451 | "metadata": {},
|
| 452 | + "outputs": [], |
| 453 | + "source": [ |
| 454 | + "u_topology, u_cell_types, u_geometry = create_vtk_mesh(V)" |
| 455 | + ] |
| 456 | + }, |
| 457 | + { |
| 458 | + "cell_type": "markdown", |
| 459 | + "metadata": {}, |
| 460 | + "source": [ |
| 461 | + "Next, we create the `pyvista.UnstructuredGrid` and add the dof-values to the mesh." |
| 462 | + ] |
| 463 | + }, |
| 464 | + { |
| 465 | + "cell_type": "code", |
| 466 | + "execution_count": 17, |
| 467 | + "metadata": {}, |
433 | 468 | "outputs": [
|
434 | 469 | {
|
435 | 470 | "data": {
|
436 | 471 | "application/vnd.jupyter.widget-view+json": {
|
437 |
| - "model_id": "026dd4bdc8354af88ecd23be302ee96c", |
| 472 | + "model_id": "54e3bc7b8f764a31836e14906e188aff", |
438 | 473 | "version_major": 2,
|
439 | 474 | "version_minor": 0
|
440 | 475 | },
|
|
447 | 482 | }
|
448 | 483 | ],
|
449 | 484 | "source": [
|
450 |
| - "plotter = pyvista.Plotter()\n", |
451 |
| - "plotter.add_mesh(grid, show_edges=True)\n", |
452 |
| - "plotter.view_xy()\n", |
| 485 | + "u_grid = pyvista.UnstructuredGrid(u_topology, u_cell_types, u_geometry)\n", |
| 486 | + "u_grid.point_data[\"u\"] = uh.x.array.real\n", |
| 487 | + "u_grid.set_active_scalars(\"u\")\n", |
| 488 | + "u_plotter = pyvista.Plotter()\n", |
| 489 | + "u_plotter.add_mesh(u_grid, show_edges=True)\n", |
| 490 | + "u_plotter.view_xy()\n", |
453 | 491 | "if not pyvista.OFF_SCREEN:\n",
|
454 |
| - " plotter.show()\n", |
455 |
| - "else:\n", |
456 |
| - " pyvista.start_xvfb()\n", |
457 |
| - " figure = plotter.screenshot(\"fundamentals.png\")" |
| 492 | + " u_plotter.show()" |
458 | 493 | ]
|
459 | 494 | },
|
460 | 495 | {
|
|
467 | 502 | },
|
468 | 503 | {
|
469 | 504 | "cell_type": "code",
|
470 |
| - "execution_count": 17, |
| 505 | + "execution_count": 20, |
471 | 506 | "metadata": {},
|
472 | 507 | "outputs": [
|
473 | 508 | {
|
474 | 509 | "data": {
|
475 | 510 | "application/vnd.jupyter.widget-view+json": {
|
476 |
| - "model_id": "2b14ac59f2cf4d129b2843ce038c4b90", |
| 511 | + "model_id": "c03cdb732aa94579ab795f0188ce9572", |
477 | 512 | "version_major": 2,
|
478 | 513 | "version_minor": 0
|
479 | 514 | },
|
|
487 | 522 | ],
|
488 | 523 | "source": [
|
489 | 524 | "if not pyvista.OFF_SCREEN:\n",
|
490 |
| - " warped = grid.warp_by_scalar()\n", |
| 525 | + " warped = u_grid.warp_by_scalar()\n", |
491 | 526 | " plotter2 = pyvista.Plotter()\n",
|
492 | 527 | " plotter2.add_mesh(warped, show_edges=True, show_scalar_bar=True)\n",
|
493 | 528 | " plotter2.show(jupyter_backend=\"ipygany\")"
|
|
503 | 538 | },
|
504 | 539 | {
|
505 | 540 | "cell_type": "code",
|
506 |
| - "execution_count": 18, |
| 541 | + "execution_count": 21, |
507 | 542 | "metadata": {},
|
508 | 543 | "outputs": [],
|
509 | 544 | "source": [
|
|
523 | 558 | " :filter: cited and ({\"chapter1/fundamentals_code\"} >= docnames)\n",
|
524 | 559 | "```"
|
525 | 560 | ]
|
526 |
| - }, |
527 |
| - { |
528 |
| - "cell_type": "code", |
529 |
| - "execution_count": null, |
530 |
| - "metadata": {}, |
531 |
| - "outputs": [], |
532 |
| - "source": [] |
533 | 561 | }
|
534 | 562 | ],
|
535 | 563 | "metadata": {
|
|
0 commit comments