diff --git a/flow360/__init__.py b/flow360/__init__.py index dea86b3e3..f397a3322 100644 --- a/flow360/__init__.py +++ b/flow360/__init__.py @@ -50,6 +50,7 @@ SpalartAllmaras, SpalartAllmarasModelConstants, TransitionModelSolver, + TurbulenceModelControls, ) from flow360.component.simulation.models.surface_models import ( Freestream, @@ -248,6 +249,7 @@ "Box", "GenericReferenceCondition", "TransitionModelSolver", + "TurbulenceModelControls", "Pressure", "TotalPressure", "Rotational", diff --git a/flow360/component/simulation/models/solver_numerics.py b/flow360/component/simulation/models/solver_numerics.py index f5b9f0fbd..b6c28ab45 100644 --- a/flow360/component/simulation/models/solver_numerics.py +++ b/flow360/component/simulation/models/solver_numerics.py @@ -10,7 +10,7 @@ from __future__ import annotations from abc import ABCMeta -from typing import Annotated, Dict, Literal, Optional, Union +from typing import Annotated, Dict, Literal, Optional, Union, List import numpy as np import pydantic as pd @@ -22,7 +22,7 @@ Flow360BaseModel, ) from flow360.component.simulation.framework.entity_base import EntityList -from flow360.component.simulation.primitives import Box +from flow360.component.simulation.primitives import Box, GenericVolume # from .time_stepping import UnsteadyTimeStepping @@ -169,7 +169,7 @@ class SpalartAllmarasModelConstants(Flow360BaseModel): C_t4: NonNegativeFloat = pd.Field(0.5) C_min_rd: NonNegativeFloat = pd.Field(10.0) - + class KOmegaSSTModelConstants(Flow360BaseModel): """ :class:`KOmegaSSTModelConstants` class specifies the constants of the SST k-omega model. @@ -202,6 +202,42 @@ class KOmegaSSTModelConstants(Flow360BaseModel): ] +class TurbulenceModelControls(Flow360BaseModel): + """ + :class:`TurbulenceModelControls` class specifies modeling constants and enforces turbulence model + behavior on a zonal basis, as defined by mesh entities or boxes in space. These controls + supersede the global turbulence model solver settings. + + Example + ______ + >>> fl.TurbulenceModelControls(modeling_constants=fl.SpalartAllmarasConstants(C_w2 = 2.718), + model_enforcement='RANS', + entities = [volume_mesh["block-1"], + fl.Box.from_principal_axes( + name="box", + axes=[(0,1,0), (0,0,1)], + center=(0, 0, 0) * fl.u.m, + size=(0.2,0.3,2) * fl.u.m)] + ) + """ + + modeling_constants: Optional[TurbulenceModelConstants] = pd.Field(None, + description="A class of `SpalartAllmarasModelConstants` or `KOmegaSSTModelConstants` used to " + + "specify constants in specific regions of the domain.") + + enforcement: Optional[Literal["RANS", "LES"]] = pd.Field( + None, description="Force RANS or LES mode in a specific control region.") + + + entities: EntityList[GenericVolume, Box] = pd.Field( + alias="volumes", + description="The entity in which to apply the `TurbulenceMOdelControls``. " + + "The entity should be defined by :class:`Box` or zones from the geometry/volume mesh." + + "The axes of entity must be specified to serve as the the principle axes of the " + + "`TurbulenceModelControls` region.", + ) + + class DetachedEddySimulation(Flow360BaseModel): """ :class:`DetachedEddySimulation` class is used for running hybrid RANS-LES simulations @@ -295,6 +331,10 @@ class TurbulenceModelSolver(GenericSolverSettings, metaclass=ABCMeta): False, description="Rotation correction for the turbulence model." ) + controls: Optional[List[TurbulenceModelControls]] = pd.Field( + None, strict=True, description="List of control zones to enforce specific turbulence modelconstants " + + "and behavior.") + class KOmegaSST(TurbulenceModelSolver): """ diff --git a/tests/simulation/converter/ref/ref_monitor.json b/tests/simulation/converter/ref/ref_monitor.json index ef7611e1f..69d38c90a 100644 --- a/tests/simulation/converter/ref/ref_monitor.json +++ b/tests/simulation/converter/ref/ref_monitor.json @@ -1 +1 @@ -{"version":"25.5.0","unit_system":{"name":"SI"},"meshing":null,"reference_geometry":null,"operating_condition":null,"models":[{"material":{"type":"air","name":"air","dynamic_viscosity":{"reference_viscosity":{"value":0.00001716,"units":"Pa*s"},"reference_temperature":{"value":273.15,"units":"K"},"effective_temperature":{"value":110.4,"units":"K"}}},"initial_condition":{"type_name":"NavierStokesInitialCondition","constants":null,"rho":"rho","u":"u","v":"v","w":"w","p":"p"},"type":"Fluid","navier_stokes_solver":{"absolute_tolerance":1e-10,"relative_tolerance":0.0,"order_of_accuracy":2,"equation_evaluation_frequency":1,"linear_solver":{"max_iterations":30,"absolute_tolerance":null,"relative_tolerance":null},"private_attribute_dict":null,"CFL_multiplier":1.0,"kappa_MUSCL":-1.0,"numerical_dissipation_factor":1.0,"limit_velocity":false,"limit_pressure_density":false,"type_name":"Compressible","low_mach_preconditioner":false,"low_mach_preconditioner_threshold":null,"update_jacobian_frequency":4,"max_force_jac_update_physical_steps":0},"turbulence_model_solver":{"absolute_tolerance":1e-8,"relative_tolerance":0.0,"order_of_accuracy":2,"equation_evaluation_frequency":4,"linear_solver":{"max_iterations":20,"absolute_tolerance":null,"relative_tolerance":null},"private_attribute_dict":null,"CFL_multiplier":2.0,"type_name":"SpalartAllmaras","reconstruction_gradient_limiter":0.5,"quadratic_constitutive_relation":false,"modeling_constants":{"type_name":"SpalartAllmarasConsts","C_DES":0.72,"C_d":8.0,"C_cb1":0.1355,"C_cb2":0.622,"C_sigma":0.6666666666666666,"C_v1":7.1,"C_vonKarman":0.41,"C_w2":0.3,"C_t3":1.2,"C_t4":0.5,"C_min_rd":10.0},"update_jacobian_frequency":4,"max_force_jac_update_physical_steps":0,"hybrid_model":null,"rotation_correction":false},"transition_model_solver":{"type_name":"None"}}],"time_stepping":{"type_name":"Steady","max_steps":2000,"CFL":{"type":"adaptive","min":0.1,"max":10000.0,"max_relative_change":1.0,"convergence_limiting_factor":0.25}},"user_defined_dynamics":null,"user_defined_fields":[],"outputs":[{"name":"R1","entities":{"stored_entities":[{"private_attribute_registry_bucket_name":"PointEntityType","private_attribute_entity_type_name":"Point","private_attribute_id":"b9de2bce-36c1-4bbf-af0a-2c6a2ab713a4","name":"Point-0","location":{"value":[2.694298,0.0,1.0195910000000001],"units":"m"}}]},"output_fields":{"items":["primitiveVars"]},"output_type":"ProbeOutput"},{"name":"V3","entities":{"stored_entities":[{"private_attribute_registry_bucket_name":"PointEntityType","private_attribute_entity_type_name":"Point","private_attribute_id":"a79cffc0-31d0-499d-906c-f271c2320166","name":"Point-1","location":{"value":[4.007,0.0,-0.31760000000000005],"units":"m"}},{"private_attribute_registry_bucket_name":"PointEntityType","private_attribute_entity_type_name":"Point","private_attribute_id":"8947eb10-fc59-4102-b9c7-168a91ca22b9","name":"Point-2","location":{"value":[4.007,0.0,-0.29760000000000003],"units":"m"}},{"private_attribute_registry_bucket_name":"PointEntityType","private_attribute_entity_type_name":"Point","private_attribute_id":"27ac4e03-592b-4dba-8fa1-8f6678087a96","name":"Point-3","location":{"value":[4.007,0.0,-0.2776],"units":"m"}}]},"output_fields":{"items":["mut"]},"output_type":"ProbeOutput"}],"private_attribute_asset_cache":{"project_length_unit":null,"project_entity_info":null, "use_inhouse_mesher": false, "use_geometry_AI": false}} +{"version":"25.5.0","unit_system":{"name":"SI"},"meshing":null,"reference_geometry":null,"operating_condition":null,"models":[{"material":{"type":"air","name":"air","dynamic_viscosity":{"reference_viscosity":{"value":0.00001716,"units":"Pa*s"},"reference_temperature":{"value":273.15,"units":"K"},"effective_temperature":{"value":110.4,"units":"K"}}},"initial_condition":{"type_name":"NavierStokesInitialCondition","constants":null,"rho":"rho","u":"u","v":"v","w":"w","p":"p"},"type":"Fluid","navier_stokes_solver":{"absolute_tolerance":1e-10,"relative_tolerance":0.0,"order_of_accuracy":2,"equation_evaluation_frequency":1,"linear_solver":{"max_iterations":30,"absolute_tolerance":null,"relative_tolerance":null},"private_attribute_dict":null,"CFL_multiplier":1.0,"kappa_MUSCL":-1.0,"numerical_dissipation_factor":1.0,"limit_velocity":false,"limit_pressure_density":false,"type_name":"Compressible","low_mach_preconditioner":false,"low_mach_preconditioner_threshold":null,"update_jacobian_frequency":4,"max_force_jac_update_physical_steps":0},"turbulence_model_solver":{"absolute_tolerance":1e-8,"relative_tolerance":0.0,"order_of_accuracy":2,"equation_evaluation_frequency":4,"linear_solver":{"max_iterations":20,"absolute_tolerance":null,"relative_tolerance":null},"private_attribute_dict":null,"CFL_multiplier":2.0,"type_name":"SpalartAllmaras","reconstruction_gradient_limiter":0.5,"quadratic_constitutive_relation":false,"modeling_constants":{"type_name":"SpalartAllmarasConsts","C_DES":0.72,"C_d":8.0,"C_cb1":0.1355,"C_cb2":0.622,"C_sigma":0.6666666666666666,"C_v1":7.1,"C_vonKarman":0.41,"C_w2":0.3,"C_t3":1.2,"C_t4":0.5,"C_min_rd":10.0},"update_jacobian_frequency":4,"max_force_jac_update_physical_steps":0,"hybrid_model":null,"rotation_correction":false, "controls" : null},"transition_model_solver":{"type_name":"None"}}],"time_stepping":{"type_name":"Steady","max_steps":2000,"CFL":{"type":"adaptive","min":0.1,"max":10000.0,"max_relative_change":1.0,"convergence_limiting_factor":0.25}},"user_defined_dynamics":null,"user_defined_fields":[],"outputs":[{"name":"R1","entities":{"stored_entities":[{"private_attribute_registry_bucket_name":"PointEntityType","private_attribute_entity_type_name":"Point","private_attribute_id":"b9de2bce-36c1-4bbf-af0a-2c6a2ab713a4","name":"Point-0","location":{"value":[2.694298,0.0,1.0195910000000001],"units":"m"}}]},"output_fields":{"items":["primitiveVars"]},"output_type":"ProbeOutput"},{"name":"V3","entities":{"stored_entities":[{"private_attribute_registry_bucket_name":"PointEntityType","private_attribute_entity_type_name":"Point","private_attribute_id":"a79cffc0-31d0-499d-906c-f271c2320166","name":"Point-1","location":{"value":[4.007,0.0,-0.31760000000000005],"units":"m"}},{"private_attribute_registry_bucket_name":"PointEntityType","private_attribute_entity_type_name":"Point","private_attribute_id":"8947eb10-fc59-4102-b9c7-168a91ca22b9","name":"Point-2","location":{"value":[4.007,0.0,-0.29760000000000003],"units":"m"}},{"private_attribute_registry_bucket_name":"PointEntityType","private_attribute_entity_type_name":"Point","private_attribute_id":"27ac4e03-592b-4dba-8fa1-8f6678087a96","name":"Point-3","location":{"value":[4.007,0.0,-0.2776],"units":"m"}}]},"output_fields":{"items":["mut"]},"output_type":"ProbeOutput"}],"private_attribute_asset_cache":{"project_length_unit":null,"project_entity_info":null, "use_inhouse_mesher": false, "use_geometry_AI": false}}