Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 0 deletions co_simulation/validation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ This folder contains the validation cases:

- [Mok FSI benchmark](https://github.com/KratosMultiphysics/Examples/blob/master/co_simulation/validation/fsi_mok/README.md)

- [Mok FSI benchmark IGA-FEM](https://github.com/KratosMultiphysics/Examples/blob/master/co_simulation/validation/fsi_mok_iga_fem/README.md)

- [Dam break against a flexible wall FSI benchmark](https://github.com/KratosMultiphysics/Examples/blob/master/co_simulation/validation/dam_break_flex_wall/README.md)

- [FSI Turek Benchmark](https://github.com/KratosMultiphysics/Examples/tree/master/co_simulation/validation/fsi_turek_FSI2)
66 changes: 66 additions & 0 deletions co_simulation/validation/fsi_mok_iga_fem/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Mok FSI benchmark

**Author:** [Juan Ignacio Camarotti](https://github.com/juancamarotti)

**Kratos version:** 10.2

**Source files:** [FSI-Mok IGA-FEM](https://github.com/KratosMultiphysics/Examples/tree/master/co_simulation/validation/fsi_mok_iga_fem/source)

## Case Specification

This is a 2D FSI simulation of the Mok benchmark test. It consists in a 2D convergent fluid channel that contains a flexible wall structure attached to its bottom wall. The main challenge of the test is that the densities of the fluid and the structure have a similar order of magnitude, leading to a strongly coupled problem in where large interaction between the two fields appears. The reference solutions have been taken from Mok (2001) and Valdés (2007). The following applications of Kratos are used:
* CoSimulationApplication
* MappingApplication
* MeshMovingApplication
* FluidDynamicsApplication
* StructuralMechanicsApplication
* IgaApplication
* LinearSolversApplication

The problem geometry as well as the boundary conditions are sketched below.
<p align="center">
<img src="data/Mok_benchmark_geometry.png" alt="Mok benchmark geometry." style="width: 600px;"/>
</p>

Regarding the inlet velocity, the next parabolic profile is imposed

<p align="center">
<img src="data/Mok_inlet_formula_1.png" alt="Mok inlet profile." style="width: 200px;"/>
</p>

where the time dependent reference velocity is defined as

<p align="center">
<img src="data/Mok_inlet_formula_2.png" alt="Mok velocity formula." style="width: 200px;"/>
</p>

A Newtonian constitutive law is considered in the fluid domain. The fluid characteristic parameters are:
* Density (&rho;): 956 _Kg/m<sup>3</sup>_
* Kinematic viscosity (&nu;): 0.145 _m<sup>2</sup>/s_

On the other hand, a linear elastic plane stress constitutive law with unit thickness is considered in the structure domain. The structure characteristic parameters are
* Density (&rho;): 1500 _Kg/m<sup>3</sup>_
* Elastic modulus (E): 2.30000E+06 _Pa_
* Poisson ratio (&nu;): 0.45

The time step is 0.1 seconds, while the total simulation time is 25.0 seconds.

The mesh was created with the [KratosSalomePlugin](https://github.com/KratosMultiphysics/KratosSalomePlugin/tree/master/tui_examples/mok_fsi). Check this example which can be easily adapted to different mesh sizes.

The mapping strategy employed in this simulation is the nearest neighbor mapper, specifically tailored for partitioned IGA-FEM simulations.

## Results
The structural domain for the problem described above was discretized using an IBRA mesh with Kirchhoff-Love shell elements (3-parameter formulation). For the fluid domain, a mesh consisting of approximately 6000 linear triangular elements was employed. The resulting velocity field, along with the deformed geometry, is presented below.

<p align="center">
<img src="data/flow_field_vel_t25.png" alt="Obtained velocity field (t = 25.0)." style="width: 600px;"/>
</p>

<p align="center">
<img src="data/Mok_ux.png" alt="Point A horizontal displacement comparison." style="width: 600px;"/>
</p>

## References
D.P. Mok. Partitionierte Lösungsansätze in der Strukturdynamik und der Fluid−Struktur−Interaktion. PhD thesis: Institut für Baustatik, Universität Stuttgart, 2001. [http://dx.doi.org/10.18419/opus-147](http://dx.doi.org/10.18419/opus-147)

G. Valdés. Nonlinear Analysis of Orthotropic Membrane and Shell Structures Including Fluid-Structure Interaction. PhD thesis: Universitat Politècnica de Catalunya, 2007. [http://www.tdx.cat/handle/10803/6866](http://www.tdx.cat/handle/10803/6866)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
117 changes: 117 additions & 0 deletions co_simulation/validation/fsi_mok_iga_fem/source/MainKratos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import KratosMultiphysics as KM
import KratosMultiphysics.IgaApplication
from KratosMultiphysics.CoSimulationApplication.co_simulation_analysis import CoSimulationAnalysis

# External imports
import importlib
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import griddata

import sys
import time

class CustomCoSimulationAnalysis(CoSimulationAnalysis):
def __init__(self, parameters):
"""Call the base class constructor."""
super().__init__(parameters)
self.time_history = []
self.disp_x_history_A = []
self.disp_x_history_B = []

def OutputSolutionStep(self):
super().OutputSolutionStep()

solver = self._GetSolver()

if hasattr(solver, "model") and hasattr(solver.model, "solver_wrappers"):
structure_solver = solver.model.solver_wrappers.get("structure")
if structure_solver and hasattr(structure_solver, "model"):
sub_model = structure_solver.model
model_part_name = "IgaModelPart"

if hasattr(sub_model, "HasModelPart") and sub_model.HasModelPart(model_part_name):
model_part = sub_model.GetModelPart(model_part_name)

wet_interface_sub_model_part = model_part.GetSubModelPart("Load_4")
current_time = wet_interface_sub_model_part.ProcessInfo[KratosMultiphysics.TIME]

# Only do this the first time
if not hasattr(self, "tracking_conditions_initialized"):
self.tracking_conditions_initialized = True

# Choose target locations
self.point_A = (0.50025, 0.25) # Replace with your target coordinates
self.point_B = (0.50, 0.125)

def get_closest_condition(target_point):
min_dist = float("inf")
closest_cond = None
for cond in wet_interface_sub_model_part.Conditions:
center = cond.GetGeometry().Center()
dist = (center.X - target_point[0])**2 + (center.Y - target_point[1])**2
if dist < min_dist:
min_dist = dist
closest_cond = cond
return closest_cond

self.condition_A = get_closest_condition(self.point_A)
self.condition_B = get_closest_condition(self.point_B)

# --- Evaluate displacement at A ---
condition = self.condition_A
geom = condition.GetGeometry()
N = geom.ShapeFunctionsValues()

solution_A = 0.0
for i, node in enumerate(condition.GetNodes()):
solution_A += node.GetSolutionStepValue(KratosMultiphysics.DISPLACEMENT_X) * N[0, i]

self.time_history.append(current_time)
self.disp_x_history_A.append(solution_A)

# --- Evaluate displacement at B ---
condition = self.condition_B
geom = condition.GetGeometry()
N = geom.ShapeFunctionsValues()

solution_B = 0.0
for i, node in enumerate(condition.GetNodes()):
solution_B += node.GetSolutionStepValue(KratosMultiphysics.DISPLACEMENT_X) * N[0, i]

self.disp_x_history_B.append(solution_B)

def Finalize(self):
super().Finalize()

import matplotlib.pyplot as plt

# Enable LaTeX-style rendering
plt.rcParams["text.usetex"] = True
plt.rcParams["font.family"] = "serif"

# Plot
plt.figure()
plt.plot(self.time_history, self.disp_x_history_A, label=r"$u_x$ at Point A")
plt.plot(self.time_history, self.disp_x_history_B, label=r"$u_x$ at Point B")

# Labels with LaTeX formatting
plt.xlabel(r"\textbf{Time} [s]")
plt.ylabel(r"\textbf{Displacement} $u_x$ [m]")
plt.title(r"\textbf{Displacement vs Time (Nearest Neighbor Mapper)}", fontsize=14)

# Grid and legend
plt.grid(True)
plt.legend(loc="best")

# Save and show
plt.savefig("displacement_vs_time.pdf", dpi=300, bbox_inches="tight")
plt.show()

if __name__ == "__main__":

with open("ProjectParametersCoSim.json", 'r') as parameter_file:
parameters = KratosMultiphysics.Parameters(parameter_file.read())

simulation = CustomCoSimulationAnalysis(parameters)
simulation.Run()
Loading