CadQuery / cadquery

A python parametric CAD scripting framework based on OCCT
https://cadquery.readthedocs.io
Other
3.16k stars 289 forks source link

Cadquery for wind turbine blade #497

Open kkpal3 opened 3 years ago

kkpal3 commented 3 years ago

Hi, I'm trying to use cadquery to build a wind turbine blade. I'm defining the blade sections by sections along the spanwise direction. Each section has a specific airfoil shape, twist and chord length. I have successfully build the airfoils sections along the span by inputting coordinates and closing them by polyline() function.

After all the sections are built, I define a path along the spanwise direction to do the sweep() function. However, I always get errors like "Standard_ConstructionError: BRepFIll:: profiles are inconsistent", or "Standard_NoSuchObject:BRepFill::SameNumberByPolarMethod failed", even though I use the same number of coordinates for each airfoil section! I believe this problem is caused by the different airfoil shape along the span, as I can successfully build the blade using the same airfoil for all spanwise locations.

Does anyone have suggestions how to solve this problem? Many thanks!

jmwright commented 3 years ago

I think that @winksaville has done some work along these lines.

Potentially related discussion: https://groups.google.com/g/cadquery/c/_7JI1Ffl2N4/m/LbVVfSC3CAAJ

There might be some potentially useful info here, although loft is being used instead of sweep.

Is there a simple example you can post of what you're trying to accomplish?

kkpal3 commented 3 years ago

Thank you Jeremy! I will have a look the references you mentioned. Meanwhile, here is a sketch of what I want to do, and a test case is also attached. Picture1 testCase.zip

I have information of the blade stored in "BladeInfo.dat". It specifies the the following: BlSpan: spanwise location of the airfoil section BlTwist: local twist angle of the airfoil section BlChord: local chord length of the airfoil BlAFID: the index of airfoil type. The coordinates of different airfoils are stored in files named nacaxxxx.txt. They have the same number of points for different airfoils.

For now, I can build the airfoil sections in cad-query. I wanted to construct the blade from these sectional data. If I use the same type of airfoils, i.e., the last column of "BladeInfo.dat" (BlAFID) having the same value, the sweep operation is successful. However, when I use different values of BlAFID, errors as I mentioned previously occurs!

adam-urbanczyk commented 3 years ago

I can run your code without any issue using the master version of CQ / CQ-editor. Which version are you using?

image

marcus7070 commented 3 years ago

I can run your code without any issue using the master version of CQ / CQ-editor.

@adam-urbanczyk just to be sure, the example as @kkpal3 provided it does run, but when you modify the provided BladeInfo.dat and change one of the numbers in the last column to eg. 2, then it doesn't run. Is that the case for you?

When I change the last profile from 1 to 2, I get about 5 minutes of 100% cpu usage then Standard_ConstructionError: BRepFill :: profiles are inconsistent.

kkpal3 commented 3 years ago

Thank you @adam-urbanczyk and @marcus7070 for the discussions, and sorry for not being clear about my questions. Yes, I meant when I use a different type of airfoil along the spanwise direction, for example, change the last profile from 1 to 2, it will give me errors.

I just checked my code again and found that I made a mistake!! I was not using the same number of points for the airfoil type 1, naca 6412. Once I discard this type and use the rest of the three airfoils for the test, cad-query seems to work well!!

Capture

adam-urbanczyk commented 3 years ago

Good to hear @kkpal3 . You might be also interested ins using spline instead of polyline and note that one profile is misisng or the spine should not start at (0,0,0). You can also just used loft and not specify any extrusion path at all.

kkpal3 commented 3 years ago

Thanks @adam-urbanczyk for the suggestions. I investigated my codes a little bit more, and found that the sweep operation still failed when there is a large change in the sectional geometry, for example, from a circle to a thin airfoil, using the same number of points for both geometries. Anyway, I will try what you suggested and report more thorough results later.

adam-urbanczyk commented 3 years ago

Did you mange to get some interesting result @kkpal3 ? I'm really curious.

kkpal3 commented 3 years ago

Sorry for the delay @adam-urbanczyk. I haven't got a satisfactory wind blade model yet. I will explain what I have tried so far. Let me know if you have any suggestions! The code is here. dtuTest.zip

Firstly, there is always problem when I try to loft over more than 2 blade sections whose shape changes drastically, say from circle to airfoil, see the fig below. Picture1

Secondly, even with similar airfoil shapes, there seems to be wiggles over a large number of sections, which is undesirable, see the fig below. Picture2

Thirdly, sweep seems to perform inferior to loft, so I did not try it much. Picture3

The best I can get so far is to loft segment-by-segment, as loft with two any TWO sections always work nicely. However, when using a lot number of sections, this approach also results in error (this error can be reproduced when using "BladeInfo.dat" instead of "BladeInfo2.dat", the latter is an abridged version of the former). The problem with this approach is that the surface of the blade is no longer smooth, as the slope at intersecting airfoil sections of two loft process is not ensured to match.

parnoldx commented 3 years ago

For wings a Gordon algorithm would be a better fit imo. Not sure if it can be made easily available but here they ported it to python from tigl c++ https://github.com/tpaviot/pythonocc-core/issues/409

adam-urbanczyk commented 3 years ago

@kkpal3 I could not get this to work either. One way to slightly improve the situation is to use BRepOffsetAPI_ThruSections.SetMaxDegree from OCC (not exposed currently). Probably you'll need to investigate using Gordon Surface for this as mentioned above. It is not implemented in CQ (PR would be very welcome). You could use https://github.com/DLR-SC/tigl or https://github.com/tomate44/CurvesWB to check if it solves the issue.

kkpal3 commented 3 years ago

Thanks for the comments. I just found a piece of code based on open cascade here. It seems to work nicely. I'm very new to open cascade, but do you think it's possible to implement it in cadquery?

Capture

adam-urbanczyk commented 3 years ago

Interesting, I must say I find it difficult to follow the intent of the code you linked to. It seems that it is using multiple lofts with additional smoothing. CadQuery is based on OCP which wraps opencascade/OCCT so you could in principle directly translate the code to Python.

kkpal3 commented 3 years ago

Hi, I just learned that it is possible to directly use opencascade method in CadQuery in here. I would like to try to translate this BB3D code into an plugin and use it in CadQuery to make the wind turbine blade.

However, I'm stuck at the first step... Using the following tutorial code in CQ would result in an error "name BRepPrimAPI_MakeBox is not defined". return cq.Shape.cast(BRepPrimAPI_MakeBox(gp_Ax2(Vector(-0.1, -1.0, -1.5), Vector(0, 0, 1)), 1.0, 2.0, 3.0).Shape())

How can I link/include the Opencascade functionality in CQ correctly?

adam-urbanczyk commented 3 years ago

You need to import it first: from OCP.BRepPrimAPI import BRepPrimAPI_MakeBox. Not that you'll also need to use gp_Vec and not Vector.

joaotcarvalho commented 1 year ago

Hello, I have a similar code to create a fan wing. I did the same operations mentioned by @kkpal3, however, the final result that I get is a hollow solid, since i created a loft between a set of airfoils created as wires.

Capturar

What I want, however, is a rigid solid body. How could I change the code to get to the result I want?

jmwright commented 1 year ago

@joaotcarvalho Can you share sample code that produces the result above?

joaotcarvalho commented 1 year ago

Yes, sure! The code and the data (3d points for the blade's airfoil) are attached. You can unzip the file and open the script in Cq-Editor to see the result.

This is what I found in the documentation regarding "cq.Solid.makeLoft", but for some reason it seems that the conversion to faces is just not possible for me, and I don't know how to fix it.

"makes a loft from a list of wires The wires will be converted into faces when possible– it is presumed that nobody ever actually wants to make an infinitely thin shell for a real FreeCADPart"

github_issue.zip

adam-urbanczyk commented 1 year ago

Here is a workaround. Currently loft is unable to cap non-planar sections, so I did that manually using makeNSidedSurface.

#%%
import pandas as pd
import cadquery as cq
import os

from cadquery.vis import show

#%%
path = os.getcwd()
print("\n", path)
airfoil_pts_dict = {}
for i in range(11):
    airfoil_df = pd.read_table(path+"\\data\\perfil_{}.txt".format(i), sep=" ", names=['X', 'Y', 'Z'])
    airfoil_pts = []
    for row in range(len(airfoil_df)):
        airfoil_pts.append(tuple(airfoil_df.loc[row]))
    airfoil_pts_dict["airfoil_{}_pts".format(i)] = airfoil_pts

airfoil_splines_dict = {}
for i in airfoil_pts_dict:
    airfoil_splines_dict["spline_{}".format(i)] = cq.Workplane("XY").spline(airfoil_pts_dict[i]).close().wire().val()

sections = list(airfoil_splines_dict.values())
cap0 = cq.Face.makeNSidedSurface(sections[:1],[])
cap1 = cq.Face.makeNSidedSurface(sections[-1:],[])

sides = cq.Solid.makeLoft(sections).Faces()

shell = cq.Shell.makeShell(sides + [cap0, cap1])
result = cq.Solid.makeSolid(shell)

#%%
show(result, *sections)

afbeelding

joaotcarvalho commented 1 year ago

Works fine! Thank you very much for the help :)