Skip to content

Instantly share code, notes, and snippets.

@bradyrx
Last active March 17, 2020 17:16
Show Gist options
  • Save bradyrx/d7a4416674638f16ac1bd9631654b137 to your computer and use it in GitHub Desktop.
Save bradyrx/d7a4416674638f16ac1bd9631654b137 to your computer and use it in GitHub Desktop.

Lagrangian Particle Visualizations in ParaView

Author: Riley X. Brady

Date: March 17th, 2020

Note: This is a very early draft. I'll likely expand this into a blog post in the future.

Pre-Processing

The particles first need to be pre-processed to work in ParaView. At the base level, our particles are saved out in netCDF history files with xParticle, yParticle, zParticle, zLevelParticle (depth).

We use this script to convert the raw netCDF into VTK files: https://gist.github.com/bradyrx/b9d8ba50ab42372521d2501f82fead97. This creates VTK "Points" data with the appropriate x, y, and z labeling it is seeking. All other variables (like depth, temperature, latitude and longitude, etc.) get carried along. What's crucial is that the x/y/z information is encoded in the x/y/z entries, e.g. pointsToVTK(f_out, x, y, z, data=particleData) in the script. This helps the particle filter in ParaView recognize how to draw the pathlines behind the particle.

NOTE:

If you only have lat/lon on the particles, we use this function to convert from x, y, z to lat/lon. I'm sure it can be worked backwards to find how to go from lat/lon to x, y, z:

subroutine convert_latlon_from_xyz(lat, lon, x, y, z) !{{{
    implicit none

    ! given xyz coordinates determine the latitude and longitude
    real(kind=RKIND), intent(out) :: &
         lat, & !< Output: latitude of point
         lon    !< Output: longitude of point

    real(kind=RKIND), intent(in) :: &
         x,   & !< Input: x position of point
         y,   & !< Input: y position of point
         z      !< Input: z position of point

    real(kind=RKIND) :: r      !< Computed: radius of earth

    r = sqrt(x*x + y*y + z*z)
    lon = atan2(y, x)
    lat = asin(z/r)

    ! ensure range in 0, 2*pi
    if (lon < 0.0_RKIND) then
      lon = 2*pii + lon
    end if

  end subroutine convert_latlon_from_xyz !}}}

ParaView

  1. After setting up your Eulerian mesh, bathymetry/topography, etc. in ParaView, load in the particles VTK file. There will probably be a file for each time step, so you load in the .pvd file containing all time steps.

  2. Apply the Temporal Interpolation filter to the object, leaving all arguments blank in the filter. If you save out an animation, this interpolates the particle paths smoothly if you have more frames than time steps in the particle trajectories.

  3. Apply TemporalParticlesToPathlines filter to your particles. The "Mask Points" option says how many particles you want to mask. If you enter 1, you'll get all particles, 2 is every other, and so on. "Max Track Length" is how many time steps to retain when drawing the pathlines. I think of it like the old arcade game snake. The tail will disappear at the max track length value. If you have 180 time steps and enter 180 here, you'll have the whole path plotted. "Max Step Distance" will remove particles that move a certain distance (buggy particles). Our particles have true cartesian x/y/z information, so I make this 1e6 since it's moving in units of meters around the Earth's surface at 2-day output. This just ensures I keep all the particles.

  1. This creates a Pathlines and Particles object in the viewer. The Particles object shows the current location of the particle. You can make this a sphere for instance. The Pathlines will show up as you step forward in time in Paraview. These are the pathlines of the particle trajectory history. You can color these lines by a variable, particleID, or just make them a solid color.

NOTE: The biggest thing to learn is that you have to actually manually step through each time step to draw the pathlines. You can't just jump to time step 100 and have the whole path drawn. Paraview draws the path as the particles move. So once you have everything set up, click it forward a few steps to make sure it looks good before drawing out the whole path (i.e. pressing the "play" button and moving through all time steps).

Once I have everything working, I do "Save Animation" with pngs and save out every frame to make into a movie with ffmpeg or DaVinci Resolve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment