Space Transformations
A Cartesian grid can be used as the starting point to define a more complex structured grid through any arbitrary non-linear transformation:
GeometricTools.transform!
— Functiontransform!(grid::Grid, f)
Applies the space transformation given by function f
to the grid, where the position of every node is given to the function f
.
GeometricTools.lintransform!
— Functionlintransform!(grid::Grid, M::Array{Float64,2}, T::Array{Float64,1})
Rotates and translates the grid by the rotation matrix M
and translation vector T
(linear transformation).
GeometricTools provides the following non-linear orthogonal space transformations: cylindrical3D(X)
, cylindrical2D(X)
, spherical3D(X)
, parabolic3D(X)
, paraboloidal3D(X)
, elliptic3D(X; a=1)
, prolate3D(X; a=1)
, oblate3D(X; a=1)
, bipolar3D(X; a=1)
, toroidal3D(X; a=1)
, and conical3D(X; b=2, c=1)
.
For linear transformations, rotation_matrix(yaw::Real, pitch::Real, roll::Real)
returns the rotation matrix of such angles, and axis_rotation(r::Array{Float64, 1}, angle_deg::Float64)
returns the transformation matrix of rotation around an arbitrary axis of unit vector r
.
The user can also define an arbitrary space transformation. The airfoil example in the Looped Grid section shows the example of transforming a quasi-one-dimensional line into an two-dimensional airfoil contour.
Example — 2D circular grid
To demonstrate the use of space transformations, in this example we generate a two-dimensional circular grid. First we define the boundaries of the circular section $r_\text{min}, r_\text{max}, \theta_\text{min}, \theta_\text{max}$ as a cartesian grid of minimum and maximum bounds $P_\text{min}=(r_\text{min}, \theta_\text{min})$ and $P_\text{max}=(r_\text{max}, \theta_\text{max})$, respectively. We then applying a cylindrical transformation on the grid. The cylindrical transformation takes the current $x,y$ coordinates of the grid as $r,\theta$ for the new grid. In this case, $r_\text{min}=R/4$, $r_\text{max}=R$, $\theta_\text{min}=0^\circ$, $\theta_\text{max}=270^\circ$, as shown below.
import GeometricTools as gt
file_name = "circulargrid00" # Output file
paraview = true # Whether to visualize the grid in Paraview
R = 1.0 # Radius of circle
P_min = [R/4, 0*pi/180] # Lower boundaries r, theta
P_max = [R, 270*pi/180] # Upper boundaries r, theta
NDIVS = [15, 60] # 15 radius divisions, 60 angle divisions
# Generate the Cartesian grid
grid = gt.Grid(P_min, P_max, NDIVS)
# Convert grid to cylindrical
gt.transform!(grid, gt.cylindrical2D)
# Visualization
if paraview
# Output a vtk file
gt.save(grid, file_name; format="vtk")
# Call paraview
run(`paraview --data=$file_name.vtk`)
else
# Use PyPlot instead of Paraview
gt.plot(grid; labelnodes=!true, labelcells=!true, labelndivs=true)
end;
Notice that NDIVS
can still be used to defined sections of refinement:
import GeometricTools as gt
file_name = "circulargrid01" # Output file
paraview = true # Whether to visualize the grid in Paraview
NDIVS = [ # r sections
[(1.0, 15, 5.0, true)],
# theta sections
[(1/3, 15, 1/3, false),
(1/3, 15, 3.0, true),
(1/3, 15, 3.0, false)]
]
# Generates the grid as cartesian
grid = gt.Grid(P_min, P_max, NDIVS)
# Converts to cylindrical
gt.transform!(grid, gt.cylindrical2D)
# Visualization
if paraview
# Outputs a vtk file
gt.save(grid, file_name; format="vtk")
# Calls paraview
run(`paraview --data=$file_name.vtk`)
else
# Use PyPlot instead of Paraview
gt.plot(grid; labelnodes=!true, labelcells=!true, labelndivs=true)
end;