Skip to content

OpenSG mesh segments #58

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions docs/user-guide/solid_models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,25 @@ Pure solid model (explicitly descritezed sandwich panels)
=========================================================

Pure solid models can be made in Sierra SM, Sierra SD or Abaqus.
Currenly only SD is partially supported since it does not allow for
spatially varying material orientations.


Continuous meshes in Sierra
----------------------------

#. The first step is to make a Genesis mesh file and the associated files with
:py:func:`~pynumad.analysis.cubit.make_blade.cubit_make_solid_blade`. This
will create the following file
#. The first step is to make a solid element Cubit model with
:py:func:`~pynumad.analysis.cubit.make_blade.cubit_make_solid_blade`.

* {wt_name}.g. Genesis mesh file.
#. The next step is to compute material orientation vectors for each element with
:py:func:`~pynumad.analysis.cubit.make_blade.get_material_orientation_vectors`.

#. The next step is to Compute material orientation with
:py:func:`~pynumad.analysis.cubit.make_blade.compute_material_orientations`
#. If Sierra SD is a target model, these orientation vectors can be assigned directly with
:py:func:`~pynumad.analysis.cubit.make_blade.assign_material_orientation_vectors`.

#. Next, the orientation data needs to be assigned with
:py:func:`~pynumad.analysis.cubit.make_blade.assign_material_orientations`
#. If Sierra SM is a target model, the orientation vectors need to be converted to Euler Angles with
:py:func:`~pynumad.analysis.cubit.make_blade.get_material_orientation_angles`.

#. The Euler Angles are then assigned to the mesh with
:py:func:`~pynumad.analysis.cubit.make_blade.assign_material_orientation_angles`.

#. Finally, the mesh needs to be exported in Genisis format
.. code-block:: python
Expand Down Expand Up @@ -62,7 +64,7 @@ Continuous meshes in Sierra
#. AND/OR run Sierra SD with: launch -n 10 salinas -i sd.i, where n is the
number of CPUs.

An example called `cubit_solid.py` exists in the examples folder.
An example called `cubit_solid.py` exists in the examples folder illustrates these steps.

Discontinuous meshes in Abaqus
------------------------------
Expand Down
10 changes: 6 additions & 4 deletions examples/cubit_solid.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,21 +80,23 @@ def get_cs_params():

#Make Cubit Geometry
station_list = [2,3]
materials_used=cubit_make_solid_blade(blade, wt_name, settings, cs_params, stationList=station_list)
materials_used, volume_dict=cubit_make_solid_blade(blade, wt_name, settings, cs_params, stationList=station_list)

#Compute material orientation
orientation_data=compute_material_orientations(cs_params['element_shape'],ncpus = 1)
orientation_vectors=get_material_orientation_vectors(volume_dict,ncpus = 1)
orientation_angles=get_material_orientation_angles(orientation_vectors)

#assign material orientation in Cubit
assign_material_orientations(orientation_data)
assign_material_orientation_vectors(orientation_vectors)
assign_material_orientation_angles(orientation_angles)

#Export mesh in Genisis format
cubit.cmd(f'export mesh "{wt_name}.g" overwrite')


#Write Sierra input file
from pynumad.paths import SOFTWARE_PATHS
template_path=SOFTWARE_PATHS['pynumad']+'src/data/templates/'
template_path=SOFTWARE_PATHS['pynumad']+'src/pynumad/data/templates/'

write_sierra_sm_model(template_path+'sm.i.template',wt_name,station_list,blade,materials_used,'.')

Expand Down
155 changes: 10 additions & 145 deletions src/pynumad/analysis/cubit/connect_cross_sections.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ def get_spanwise_splines_for_a_volume(current_surface_id,next_surface_id,spanwis



def make_all_volumes_for_a_part(surface_dict, ordered_list, i_station_end,spanwise_splines):
def make_all_volumes_for_a_part(surface_dict, volume_dict,ordered_list, i_station_end,spanwise_splines):
# nIntervals=3
vol_list=[]
i_start = len(spanwise_splines)
Expand All @@ -384,8 +384,14 @@ def make_all_volumes_for_a_part(surface_dict, ordered_list, i_station_end,spanwi
spanwise_splines_for_a_volume = get_spanwise_splines_for_a_volume(current_surface_id,next_surface_id,spanwise_splines[part_surface_ids],
surface_dict[current_surface_id]["verts"],surface_dict[next_surface_id]["verts"])
make_a_volume(i_span,current_surface_id,next_surface_id,spanwise_splines_for_a_volume,surface_dict,i_station_end)
vol_list.append(get_last_id("volume"))
# assign_intervals(get_last_id("volume"),nIntervals)
vol_id = get_last_id("volume")
vol_list.append(vol_id)

volume_dict[vol_id] = {}
# volume_dict[vol_id]["material_name"] = material_name
volume_dict[vol_id]["ply_angle"] = surface_dict[current_surface_id]["ply_angle"]
del surface_dict[current_surface_id]

else:
raise ValueError("Can't make volumes with only one cross section.")

Expand Down Expand Up @@ -529,60 +535,7 @@ def make_birds_mouth(
return list(parse_cubit_list("volume", parse_string)) #update the web volumes


# cubit.cmd('open "/home/ecamare/myprojects/bar/cubitDev/python/python0.cub"')


# def get_approximate_thickness_direction_for_volume(volume_id):
# # This function is used when assigning material orientations

# # Get thickness direction tangents

# #Get list of curves with name layer_thickness
# parse_string = f'with name "*thickness*" in volume {volume_id}'
# thickness_curve_ids = parse_cubit_list("curve", parse_string)

# approximate_thickness_direction = []
# for i_curve in thickness_curve_ids:
# current_curve=cubit.curve(i_curve)
# coords = current_curve.position_from_fraction(0.5)
# approximate_thickness_direction.append(current_curve.tangent(coords))
# approximate_thickness_direction = np.array(approximate_thickness_direction)
# n_thickness_curves=len(thickness_curve_ids)
# # approximate_thickness_direction = []
# # for current_curve in cubit.volume(volume_id).curves():
# # curve_name = cubit.get_entity_name("curve", current_curve.id())
# # if "layer_thickness" in curve_name:
# # coords = current_curve.position_from_fraction(0.5)
# # approximate_thickness_direction.append(current_curve.tangent(coords))
# # approximate_thickness_direction = np.array(approximate_thickness_direction)
# # n_thickness_curves, _ = approximate_thickness_direction.shape

# if n_thickness_curves == 4: # All other cases
# return np.mean(approximate_thickness_direction, 0)
# elif n_thickness_curves == 8: # LE adhesive case and round TE adhesive
# return 0
# elif n_thickness_curves == 6: # Web overwrap
# # Take the mean of all curves with name 'layer_thickness'
# mean = np.mean(approximate_thickness_direction, 0)

# errorList = []
# for i in range(n_thickness_curves):
# diff = approximate_thickness_direction[i] - mean

# errorList.append(sqrt(dotProd(diff, diff)))
# sortIndex = np.argsort(errorList)[:4] # Take the first four.
# # This discards the two directions
# # with the largest deviation from the
# # average

# return np.mean(approximate_thickness_direction[sortIndex, :], 0)
# else:
# cubit.cmd(f'save as "Debug.cub" overwrite')
# raise ValueError(
# f"The number of thickness curves in volume is unexpected. Cannot assign material orientation. n_thickness_curves: {n_thickness_curves}"
# )

# return


def get_mat_ori_surface(volume_id):

Expand Down Expand Up @@ -619,92 +572,4 @@ def get_mat_ori_surface(volume_id):
else:
sign = -1.0
return mat_ori_surface,sign
def old_get_mat_ori_surface(volume_id, spanwise_mat_ori_curve):
# This function is used when assigning material orientations
# This gets returns the surface within a volume that will be used to get surface normals.
# The sign +-1 is also returned since some of the surfaces are oriented the wrong way

approximate_thickness_direction = get_approximate_thickness_direction_for_volume(volume_id)


surface_ids = []
volumeSurfaces = cubit.volume(volume_id).surfaces()
for current_surface in volumeSurfaces:

parse_string = f'with name "*thickness*" in surface {current_surface.id()}'
thickness_curve_ids = parse_cubit_list("curve", parse_string)

if len(thickness_curve_ids)==0:
surface_ids.append(current_surface.id())

# # Create a list of surface IDs in the given volume
# surface_ids = []
# volumeSurfaces = cubit.volume(volume_id).surfaces()
# for current_surface in volumeSurfaces:
# surface_ids.append(current_surface.id())

# # Eliminate surfaces that have two curves named thickness:
# surface_ct = 0
# for current_surface in volumeSurfaces:
# curve_ct = (
# 0 # Counts the number of curves in the surface with name 'layer_thickness'
# )
# for current_curve in current_surface.curves():
# curve_name = cubit.get_entity_name("curve", current_curve.id())
# if "layer_thickness" in curve_name:
# curve_ct += 1

# if curve_ct >= 2:
# surface_ct += 1
# surface_ids.remove(current_surface.id())

# surface_ids now has the list of surfaces w/o thickness curves
if len(surface_ids) == 3 or len(surface_ids) == 2 or len(surface_ids) == 1:
if len(surface_ids) == 2:
surface_name = cubit.get_entity_name("surface", surface_ids[0])
if "topFace" in surface_name:
surface_id = surface_ids[0]
else:
surface_id = surface_ids[-1]
elif len(surface_ids) == 1: # Web overwrap
surface_id = surface_ids[0]
elif len(surface_ids) == 3:
if 'web' in cubit.get_entity_name("volume", volume_id).lower():
#This is for when birdsmouth is made and it does
#not cut into the next station
max_area=0
for i_surf in surface_ids:
area =cubit.surface(i_surf).area()
if area > max_area:
max_area=area
surface_id=i_surf
else:
raise ValueError(
"The number of thickness curves in volume is unexpected. Cannot assign material orientation"
)

coords = cubit.get_center_point("surface", surface_id)
surface_normal = cubit.surface(surface_id).normal_at(coords)

if dotProd(surface_normal, approximate_thickness_direction) > 0:
sign = 1.0
else:
sign = -1.0




elif len(surface_ids) == 0:

# LE adhesive and/or TE adhesive for round cross-sections
# print(f'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~volume_id {volume_id}')
surface_id = False
sign = 1.0
#parse_string = f'with name "*layer_thickness*" in volume {volume_id}'
#thickness_curve_ids = parse_cubit_list("curve", parse_string)
else:
raise ValueError(
"The number of thickness curves in volume is unexpected. Cannot assign material orientation"
)

return surface_id, sign
Loading