Skip to content
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

New fatigue example #405

Merged
merged 47 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
761a0f7
Add function to extract ply wise data
janvonrickenbach Dec 7, 2023
9bd530f
Add test for extract ply wise data
janvonrickenbach Dec 8, 2023
2893378
Add docs
janvonrickenbach Dec 8, 2023
b71d667
Fix title in documentation
janvonrickenbach Jan 3, 2024
28484eb
Merge branch 'main' into feat/ply_wise_plots
janvonrickenbach Jan 3, 2024
fd9fe91
Fix include
janvonrickenbach Jan 3, 2024
c728b8c
Merge remote-tracking branch 'origin/feat/ply_wise_plots' into feat/p…
janvonrickenbach Jan 3, 2024
18f5c9e
Update src/ansys/dpf/composites/ply_wise_data.py
janvonrickenbach Jan 3, 2024
03300a0
Update src/ansys/dpf/composites/ply_wise_data.py
janvonrickenbach Jan 3, 2024
eda75f0
Update src/ansys/dpf/composites/ply_wise_data.py
janvonrickenbach Jan 3, 2024
b8f06cf
Update filtering example
janvonrickenbach Jan 3, 2024
8329007
Merge remote-tracking branch 'origin/feat/ply_wise_plots' into feat/p…
janvonrickenbach Jan 3, 2024
c119f93
Remove port specification
janvonrickenbach Jan 3, 2024
dfa7f6a
Assign correct location
janvonrickenbach Jan 3, 2024
370f95f
Add version checks in example
janvonrickenbach Jan 3, 2024
61a5ac0
Remove auto generated type.
janvonrickenbach Jan 3, 2024
dafed86
Skip tests for older versions
janvonrickenbach Jan 3, 2024
dca10aa
Fix link in docs
janvonrickenbach Jan 3, 2024
2bacdae
Don't override location. It is now set in the backend.
janvonrickenbach Jan 3, 2024
79d9bc9
Add fatigue example
janvonrickenbach Jan 4, 2024
0056258
Add fatigue example
janvonrickenbach Jan 4, 2024
16d0f59
Merge branch 'main' into feat/fatigue_example
janvonrickenbach Jan 4, 2024
1178a14
Update examples/006_filter_composite_data_example.py
janvonrickenbach Jan 5, 2024
fc49096
Update examples/006_filter_composite_data_example.py
janvonrickenbach Jan 5, 2024
6b59ef8
Update examples/006_filter_composite_data_example.py
janvonrickenbach Jan 5, 2024
fa11d16
Update examples/006_filter_composite_data_example.py
janvonrickenbach Jan 5, 2024
bb561c7
Update examples/006_filter_composite_data_example.py
janvonrickenbach Jan 5, 2024
aa07a7a
Update examples/006_filter_composite_data_example.py
janvonrickenbach Jan 5, 2024
327e806
Update examples/006_filter_composite_data_example.py
janvonrickenbach Jan 5, 2024
b698bc6
Update examples/006_filter_composite_data_example.py
janvonrickenbach Jan 5, 2024
b9050c8
Update src/ansys/dpf/composites/ply_wise_data.py
janvonrickenbach Jan 5, 2024
3bb1a83
Update src/ansys/dpf/composites/ply_wise_data.py
janvonrickenbach Jan 5, 2024
31073db
Update examples/012_fatigue_example.py
janvonrickenbach Jan 5, 2024
16e8ded
Update examples/012_fatigue_example.py
janvonrickenbach Jan 5, 2024
a331a39
Update examples/006_filter_composite_data_example.py
janvonrickenbach Jan 5, 2024
dc394ac
Update examples/012_fatigue_example.py
janvonrickenbach Jan 5, 2024
32ae716
Update examples/012_fatigue_example.py
janvonrickenbach Jan 5, 2024
5f541bc
Apply suggestions from code review
janvonrickenbach Jan 5, 2024
0e97a20
Merge remote-tracking branch 'origin/feat/fatigue_example' into feat/…
janvonrickenbach Jan 5, 2024
dfc1e19
Fix codestyle issues
janvonrickenbach Jan 5, 2024
7d8a0bc
Fix code style issues
janvonrickenbach Jan 5, 2024
13ac640
Document more explicitly that SpotReductionStrategy only affects aver…
janvonrickenbach Jan 5, 2024
e237bc6
Use twice the orthotropic stress limit for Sc since it represents the…
janvonrickenbach Jan 5, 2024
da258e7
Implement PR suggestion
janvonrickenbach Jan 9, 2024
38f35e6
Merge with main
janvonrickenbach Jan 15, 2024
d88a9b4
Fix merge problem
janvonrickenbach Jan 15, 2024
f00306a
Merge branch 'main' into feat/fatigue_example
janvonrickenbach Jan 15, 2024
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
2 changes: 1 addition & 1 deletion doc/source/api/ply_wise_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Ply wise data
.. autosummary::
:toctree: _autosummary

ReductionStrategy
SpotReductionStrategy
get_ply_wise_data


4 changes: 2 additions & 2 deletions examples/006_filter_composite_data_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from ansys.dpf.composites.constants import Spot, Sym3x3TensorComponent
from ansys.dpf.composites.example_helper import get_continuous_fiber_example_files
from ansys.dpf.composites.layup_info import AnalysisPlyInfoProvider, get_all_analysis_ply_names
from ansys.dpf.composites.ply_wise_data import ReductionStrategy, get_ply_wise_data
from ansys.dpf.composites.ply_wise_data import SpotReductionStrategy, get_ply_wise_data
from ansys.dpf.composites.select_indices import (
get_selected_indices,
get_selected_indices_by_analysis_ply,
Expand Down Expand Up @@ -82,7 +82,7 @@
ply_name="P1L1__ud_patch ns1",
mesh=composite_model.get_mesh(),
component=Sym3x3TensorComponent.TENSOR11,
reduction_strategy=ReductionStrategy.MAX,
spot_reduction_strategy=SpotReductionStrategy.MAX,
requested_location=dpf.locations.elemental,
)

Expand Down
156 changes: 156 additions & 0 deletions examples/012_fatigue_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
"""
.. _fatigue_plate_example:

Evaluate fatigue for a composite plate
--------------------------------------

This example shows how to evaluate fatigue for a flat plate.
It shows how you can use PyPDF Composites to select specific layers and define a custom
combination method. For this example, the custom combination method is stress in fibre
direction.

A random load time series is created. Taking into account that the load is assumed
proportional, rainflow counting is applied to the load time series.
Load ranges are then applied on the stress combination method, and damage is evaluated
by using a dummy S-N curve.

Be aware that the fatpack package is not developed by Ansys, so it is the responsibility
of the user to verify that it works as expected. For more information, see the
`fatpack package <https://pypi.org/project/fatpack/>`_,

"""


# %%
# Set up analysis
# ~~~~~~~~~~~~~~~
# Setting up the analysis consists of loading the required modules, connecting to the
# DPF server, and retrieving the example files.
#
# Load Ansys libraries and numpy, matplotlib and fatpack
import ansys.dpf.core as dpf
import fatpack
import matplotlib.pyplot as plt
import numpy as np

from ansys.dpf.composites.composite_model import CompositeModel
from ansys.dpf.composites.constants import Sym3x3TensorComponent
from ansys.dpf.composites.example_helper import get_continuous_fiber_example_files
from ansys.dpf.composites.layup_info import AnalysisPlyInfoProvider
from ansys.dpf.composites.select_indices import get_selected_indices_by_analysis_ply
from ansys.dpf.composites.server_helpers import connect_to_or_start_server

# %%
# Start a DPF server and copy the example files into the current working directory.
server = connect_to_or_start_server()
composite_files_on_server = get_continuous_fiber_example_files(server, "fatigue")

# %%
# Create a composite model
composite_model = CompositeModel(composite_files_on_server, server)

# %%
# Read stresses and define a specific layer and a component of stress tensor
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#

# %%
# Read stresses
stress_operator = composite_model.core_model.results.stress()
stress_operator.inputs.bool_rotate_to_global(False)
stress_fc = stress_operator.get_output(pin=0, output_type=dpf.types.fields_container)
stress_field = stress_fc.get_field_by_time_id(1)

# %%
# Select layer P1L1__ModelingPly.2
analysis_ply_info_provider = AnalysisPlyInfoProvider(
mesh=composite_model.get_mesh(), name="P1L1__ModelingPly.2"
)

# %%
# Select Sigma11 as the combination method
component = Sym3x3TensorComponent.TENSOR11


# %%
# Load time series and apply rainflow counting
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# A random time series is created. Load is assumed proportional, so rainflow counting
# can be directly done on the load time series to get the load ranges.
# No mean stress correction is applied.
#
number_of_times = 100
load_factor_time_series = np.random.normal(-1, 2.5, size=number_of_times)
x = np.linspace(1, number_of_times, number_of_times)
plt.xlabel("Load Index")
plt.ylabel("Load Factor")
plt.plot(x, load_factor_time_series, color="red")


# %%
# Fatpack package is used for doing the rainflow counting
load_range_factors = fatpack.find_rainflow_ranges(load_factor_time_series)


# %%
# S-N curve
# ~~~~~~~~~
# A dummy S-N curve is created. Note that this curve is not based on any
# experimental data. Sc is chosen to be twice the orthotropic stress limit in the fiber direction.
# and Nc is set to 1.
#
Sc = 2 * 1979
Nc = 1
s_n_curve = fatpack.LinearEnduranceCurve(Sc)
# Value for UD materials
s_n_curve.m = 14
s_n_curve.Nc = Nc

N = np.logspace(0, 9, 1000)
S = s_n_curve.get_stress(N)
line = plt.loglog(N, S)
plt.grid(which="both")
plt.title("Dummy Linear S-N curve")
plt.xlabel("Cycles to failure")
plt.ylabel("Stress range (MPa)")


# %%
# Damage evaluation
# ~~~~~~~~~~~~~~~~~
# Stress S11 at time 1 and layer P1L1__ModelingPly.2 are read
# for each load range. Its damage is evaluated using the dummy S-N curve.
#

damage_result_field = dpf.field.Field(location=dpf.locations.elemental, nature=dpf.natures.scalar)

with damage_result_field.as_local_field() as local_result_field:
element_ids = analysis_ply_info_provider.property_field.scoping.ids

for element_id in element_ids:
stress_data = stress_field.get_entity_data_by_id(element_id)
element_info = composite_model.get_element_info(element_id)
assert element_info is not None
selected_indices = get_selected_indices_by_analysis_ply(
analysis_ply_info_provider, element_info
)
# Load Range scaled by S11
s_11 = max(stress_data[selected_indices][:, component])
stress_ranges = load_range_factors * s_11
fatigue_damage = s_n_curve.find_miner_sum(stress_ranges)
local_result_field.append([fatigue_damage], element_id)


# %%
# Plot damage
composite_model.get_mesh().plot(damage_result_field, text="Fatigue Damage")


# %%
# Identify the element with the maximum damage
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
maximum_element_scoping = damage_result_field.max().scoping
max_element_id = maximum_element_scoping[0]
print(f"The element with highest damage is {max_element_id}.")
print(f"The highest damage value is {damage_result_field.max().data[0]}.")
Loading
Loading