Tutorial: Simulating an electric ducted fan with Coreform Flex

Overview

In this tutorial we’re going to simulate the steady-state stresses of a spinning electric ducted fan in Coreform Flex. But I also want to tell a story, a story that helps explain why we’ve developed Coreform Flex. I know that many readers, especially on this forum, will be familiar with traditional meshing workflows and the pains inherent to it. However I think this exercise will be enlightening even for the experienced analyst, while also demonstrative to the non-analyst who’s wants to understand the issues with traditional meshing.

To this end, I will first demonstrate traditional hex & tet-meshing workflows and then I will show the simulation setup procedure for this fan within Coreform Flex – which we’ll see is a meshing-free workflow that allows us to move immediately to analysis. Because this is a long post, I’ll summarize at the front.

Summary

To build an all-hex mesh on the fan geometry took me approximately 40 hours (though inefficient hours on airplanes, in airports, while watching college football) and required pretty significant defeaturing of stress-relief fillets. An all-tet mesh took me approximately an hour to construct due to some deep bug either with the CAD geometry, Coreform Cubit’s underlying CAD kernel, or mesh algorithms within Coreform Cubit, that I had to work around.

Conversely, within one hour I not only Flex-meshed the fan assembly in Coreform Flex, but I’d also setup, solved, and viewed the simulation results. Furthermore, since I was able to script the entire process in Python, future analyses of different fan geometries could be completed within minutes.

– As a final note before beginning, I ran up against our forum post character and data limits so I’ll be investigating some different forms of providing this (and other) tutorials, which should allow you to replicate tutorials directly in our tools… stay tuned!

Geometry

The geometry for this simulation comes from this GrabCAD project by the GrabCAD user chris.t-35. Here’s the STEP file for your convenience:
55mm_EDF.STEP (2.0 MB)

Challenges with traditional meshing

I would be remiss if I didn’t first talk about traditional meshing approaches.

Meshing the rotor cone

The rotor cone is fairly straightforward to mesh. We begin by recognizing that we can decompose the cone into two regions, the inner core and the outer rim, that are independently hex-meshable. We can use Coreform Cubit’s extensive geometry creation and webcutting tools to decompose it into these two major regions:

reset

# Import geometry
import step "/Path/To/55mm_EDF.STEP" heal

# Assign blocks for assembly management
block 1 vol 1
block 2 vol 2

block 1 name "fan"
block 2 name "rotor_cone"

# Mesh the rotor cone
## Cut into outer rim and inner core regions
create vertex on curve 321  close_to vertex 206  
create curve vertex 206 214 
sweep curve 338  along curve 337  
webcut volume 2  with sheet extended from surface 129 

## Cleanup temporary tool geometry
delete body 3

A limitation in Coreform Cubit is that it doesn’t support “many (surface) to many (surface)” sweeps, so we’ll cut both volumes along a plane normal to the outer curve at the vertex locations of the radial curves (the curves emanating from the tip of the cone):

webcut volume in block 2 with plane normal to curve 333  close_to vertex 203  

And then we cut these two halves in half again, using a plane normal to the midpoint of the outer curve(s):

webcut volume in block 2 with plane normal to curve 333  fraction .5 from start 

We then merge these volumes back together, to ensure a contiguous mesh, and mesh the rotor cone:

merge vol in block 2

volume in block 2 size 1
volume in block 2 scheme auto 
mesh volume in block 2

Easy enough. About one minute for me to mesh when I first got this model, I’ve had a lot of practice!

Here’s the full journal file to this point:

#!cubit
reset

# Import geometry
import step "/Path/To/55mm_EDF.STEP" heal

# Assign blocks for assembly management
block 1 vol 1
block 2 vol 2

block 1 name "fan"
block 2 name "rotor_cone"

# Mesh the rotor cone
## Cut into outer rim and inner core regions
create vertex on curve 321  close_to vertex 206  
create curve vertex 206 214 
sweep curve 338  along curve 337  
webcut volume in block 2  with sheet extended from surface 129 

## Cleanup temporary tool geometry
delete body 3

## Partition the rotor cone for meshability
webcut volume in block 2 with plane normal to curve 333  close_to vertex 203  
webcut volume in block 2 with plane normal to curve 333  fraction .5 from start 

## Enforce contiguous mesh
merge volume in block 2

## Assign mesh scheme and generate mesh
volume in block 2 size 1
volume in block 2 scheme auto 
mesh volume in block 2

Meshing the fan

Now comes the hard part: meshing the fan. Now, I’ve spent nearly 40 hours trying to hex-mesh this fan. First I have to compromise and remove the fillets on the interior of the fan:

remove surface 117 115 116 118  extend 
Surface 110  copy nomesh
sweep surface 110   perpendicular distance 1 
remove surface 4 114 113 112 extend
webcut Volume 1 tool Body 11  
delete Body 11  
delete volume 1

So that I can again separate the fan into an inner core region an an outer “ring”

webcut volume 12  sweep surface 198  perpendicular inward through_all 

Now, since we know the inner region is now meshable, let’s turn our attention to the outer “ring”. A trick I often do with objects with rotational symmetry is: chop it into a symmetric section, make the subsection hex-meshable, create rotational pattern of the meshable subsection, imprint and merge:

create vertex on curve 84 86  midpoint 
create vertex on curve 242  close_to vertex 107 93 94 80  
create curve arc  three vertex 335 337 338  
split curve 539  close_to vertex 336 337  
create vertex on curve 540  midpoint 
create vertex on curve 542  midpoint 
create curve vertex 333 345  
create curve vertex 334 346  
create vertex on curve 543 544  midpoint 
create vertex location on surface 59  close_to location at vertex 347    
create vertex location on surface 59  close_to location at vertex 348    
webcut volume 13  with plane vertex 333  vertex 349  vertex 345  
webcut volume 13  with plane vertex 334  vertex 350  vertex 346  
delete volume 13, 15
delete curve all
delete vertex all

Which produces this symmetric section:

Which we can “preview” how this piece would be rotationally instanced:

create vertex center curve 660  
create vertex center curve 656  

#!python
c = cubit.surface(288).center_point()
n = cubit.surface(288).normal_at( c )
cubit.cmd( f"Volume 16  copy reflect origin {c[0]} {c[1]} {c[2]}  direction {n[0]} {n[1]} {n[2]}  nomesh  preview" )

#!cubit
Volume 16  copy rotate 40 about vertex 409 410 repeat 8 nomesh 

But here is the issue… try as I might… I cannot get an all-hex mesh (of good element quality) on this blade subsection without removing the fillets along the base of the blade. I’ve spent four airplane rides (plus layovers), a few sleepless nights with a newborn, and a few stressful college football games trying to mesh this single blade part. The approaches I’ve attempted to use run into very minor numerical errors during projection that result in bad CAD, but even if my attempts did work, I’m still not convinced the blade would be all-hex meshable due to the large angle of the fillets:

As a challenge to the community, to the first person to build a quality, all-hex mesh on either of the below CAD files that can be “pinwheeled” back to the full fan mesh I will send you a coffee cup with a Coreform Cubit logo and an image of your meshed blade. Note that I will roughly define quality as being a min( Scaled Jacobian ) ≥ 0.25 for the mesh.

single_blade.stp (177.1 KB)
single_blade.sat (316.9 KB)

Instead I remove the fillets and then do some fancy webcutting:

to obtain a mesh of my desired quality:

Great! So I can get a hex-mesh… but at what cost? Not only have I spent many hours producing this mesh, but I’ve also removed potentially critical features from my geometry. I’ll need to proceed with my analysis carefully to understand what the response is in the now missing fillets. Usually, I’d conduct breakout models to understand the correlation between a global response and the stresses in those fillets… more work!

This is so expensive, that for a linear analysis we’d have thrown in the towel and just used a quadratic tetrahedral mesh. Though even this requires a fair bit of manual preprocessing - compositing small surfaces and curves that lead to tet-meshing errors. Even with tet-meshing it’s common that “fire and forget” workflows fall down on complex CAD geometries:

Reviewing traditional meshing

I’ve shared this meshing “journey” to help you better understand the pain that meshing can bring to a finite element analyst. Even though I love Coreform Cubit and am convinced it’s the best meshing experience available, for novices and experts alike, meshing is simply an incredibly difficult problem. Now, with this as our backdrop… let’s look at a better approach… a meshing-free approach with Coreform Flex!

A meshing-free solution with Coreform Flex

Meshing, actually

We begin by importing our STEP file into Coreform Flex:

And now let’s mesh the fan by opening the Meshes manager at top right, and then click the + button next to the part named fan (note that just prior, I renamed the two parts from the Deutsch names in the STEP file):

Which produces the following background mesh:

We don’t yet have the best heuristics for the initial mesh size, so we do need to change our mesh size manually.


I suppose technically this means we’re still meshing, but recognize that I’ve gone from 40+ hours to produce a mesh on a defeatured fan, to mere seconds to define my mesh on a fully-featured geometry. Next we mesh the cone:

If I want to preview the trimmed mesh that will be computed at simulation submission, I can setup a Trim job in the Jobs manager:

And after the job completes (~4 minutes on my laptop’s 6 cores) click the :eye: icon to render the trimmed mesh:

(Note: the missing surfaces - e.g., bottom left - are where we use a fallback scheme that we don’t yet support rendering)

And that’s it, I’m done meshing! Now let’s setup the simulation.

Simulation setup

Our entry-point is through the Procedures object in our IGA model-tree… click the + button

Our goal will be to complete the entries that define our procedure (Currently we only support single-procedure simulations, multi-procedure coming soon!). As we click on the various + buttons, a “breadcrumb” will open that provides a focused view to the model tree.

Creating the Flex Model

We begin by creating our Flex Model – essentially, our simulation assembly:

Note that we need to create materials for the analysis (as indicated by the select item text). Clicking the + next to the Material field will take our breadcrumb interface to the material scope, where we create an aluminum material (using the MMTS consistent unit system):

And then, clicking the Back to Flex Model Definitions button we make our selections:

Intervals

We then create an interval for the simulation – we’re going to just perform a linear static analysis, so our “time” interval will be the unit-interval:

Timesteppers

We then create our linear statics timestepper:

Which needs a linear equation solver:

Boundary conditions

We then create a boundary condition – holding the surfaces at the center of the fan.

Along the way, we’ll create a function that returns the scalar 1, so that we can then specify a scale_factor = 0 to hold the surfaces fixed:

And we need to create a set for our boundary conditions. Clicking the + next to Set will open the Set Manager and we make our selection(s):

Load conditions

Next we’ll create the centrifugal forces applied to the fan and core. Currently, Coreform Flex doesn’t have a wide variety of available load condition types but we can use a Julia subroutine to define a body force:

The contents of that Julia file are:

using LinearAlgebra: dot
function centrifugal_force( pos, time )
    mass = 2.712e-9
    ang_vel = 5235.0 # #rad/s -- approx 50,000 RPM
    # Define axis of rotation
    x0 = [ -0.000039, 0.499768, 7.323488]
    x1 = [ 0, 5.257811, -10.433768]
    axis = x1 - x0
    # Project `pos` onto the line defined by x0 and x1
    t = dot( axis, pos - x0 ) / dot( axis, axis )
    # Compute the point on the line
    pos_line = x0 + t * ( axis )
    # Compute the radius vector
    r = pos - pos_line
    return r * mass * ang_vel*ang_vel
end

Interactions

Next we define the connection between the fan and the cone. We will use what we call a material interface – which is the functional equivalent of imprint and merge operations in Coreform Cubit that enforce a contiguous mesh.

Here, rather than click the + button, let’s define the interface manually in the Interface Manager:

Outputs

And finally, we setup our field outputs:

Results

The simulation results can then be visualized using the free, open-source visualization software: ParaView. Below we visualize just the fan component (since the rotor cone’s results aren’t of interest.

1 Like