From e10f01177855dd3c71bdffc7210974101a12e825 Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Thu, 24 Apr 2025 16:13:30 +0200 Subject: [PATCH 01/19] added operating condition from mach reynolds to aerospacecondition --- flow360/__init__.py | 2 - .../operating_condition.py | 195 +++++++++--------- .../framework/test_multi_constructor_model.py | 47 ++++- .../params/test_simulation_params.py | 7 +- .../utils/tutorial_2dcrm_param_generator.py | 8 +- 5 files changed, 144 insertions(+), 115 deletions(-) diff --git a/flow360/__init__.py b/flow360/__init__.py index dea86b3e3..ec8372d48 100644 --- a/flow360/__init__.py +++ b/flow360/__init__.py @@ -99,7 +99,6 @@ GenericReferenceCondition, LiquidOperatingCondition, ThermalState, - operating_condition_from_mach_reynolds, ) from flow360.component.simulation.outputs.output_entities import ( Isosurface, @@ -254,7 +253,6 @@ "Mach", "MassFlowRate", "UserDefinedField", - "operating_condition_from_mach_reynolds", "VolumeMesh", "SurfaceMesh", "UserDefinedFarfield", diff --git a/flow360/component/simulation/operating_condition/operating_condition.py b/flow360/component/simulation/operating_condition/operating_condition.py index 091814579..c401d5ddd 100644 --- a/flow360/component/simulation/operating_condition/operating_condition.py +++ b/flow360/component/simulation/operating_condition/operating_condition.py @@ -244,8 +244,11 @@ class AerospaceConditionCache(Flow360BaseModel): """[INTERNAL] Cache for AerospaceCondition inputs""" mach: Optional[pd.NonNegativeFloat] = None + # reynolds: Optional[pd.PositiveFloat] = None + project_length_unit: Optional[LengthType.Positive] = None alpha: Optional[AngleType] = None beta: Optional[AngleType] = None + temperature: Optional[AbsoluteTemperatureType] = None thermal_state: Optional[ThermalState] = pd.Field(None, alias="atmosphere") reference_mach: Optional[pd.PositiveFloat] = None @@ -370,6 +373,102 @@ def from_mach( reference_velocity_magnitude=reference_velocity_magnitude, ) + # pylint: disable=too-many-arguments + @MultiConstructorBaseModel.model_constructor + @pd.validate_call + def from_mach_reynolds( + cls, + mach: pd.NonNegativeFloat, + reynolds: pd.PositiveFloat, + project_length_unit: LengthType.Positive, + alpha: Optional[AngleType] = 0 * u.deg, + beta: Optional[AngleType] = 0 * u.deg, + temperature: AbsoluteTemperatureType = 288.15 * u.K, + reference_mach: Optional[pd.PositiveFloat] = None, + ): + """ + Create an `AerospaceCondition` from Mach number and Reynolds number. + + This function computes the thermal state based on the given Mach number, + Reynolds number, and temperature, and returns an `AerospaceCondition` object + initialized with the computed thermal state and given aerodynamic angles. + + Parameters + ---------- + mach : NonNegativeFloat + Freestream Mach number (must be non-negative). + reynolds : PositiveFloat + Freestream Reynolds number defined with mesh unit (must be positive). + project_length_unit: LengthType.Positive + Project length unit. + alpha : AngleType, optional + Angle of attack. Default is 0 degrees. + beta : AngleType, optional + Sideslip angle. Default is 0 degrees. + temperature : AbsoluteTemperatureType, optional + Freestream static temperature (must be a positive temperature value). Default is 288.15 Kelvin. + reference_mach : PositiveFloat, optional + Reference Mach number. Default is None. + + Returns + ------- + AerospaceCondition + An instance of :class:`AerospaceCondition` with calculated velocity, thermal state and provided parameters. + + Example + ------- + Example usage: + + >>> condition = operating_condition_from_mach_reynolds( + ... mach=0.85, + ... reynolds=1e6, + ... project_length_unit=1 * u.mm, + ... temperature=288.15 * u.K, + ... alpha=2.0 * u.deg, + ... beta=0.0 * u.deg, + ... reference_mach=0.85, + ... ) + >>> print(condition) + AerospaceCondition(...) + + """ + + if temperature.units is u.K and temperature.value == 288.15: + log.info("Default value of 288.15 K will be used as temperature.") + + material = Air() + + velocity = ( + mach if reference_mach is None else reference_mach + ) * material.get_speed_of_sound(temperature) + + density = ( + reynolds + * material.get_dynamic_viscosity(temperature) + / (velocity * project_length_unit) + ) + + thermal_state = ThermalState(temperature=temperature, density=density) + + velocity_magnitude = mach * thermal_state.speed_of_sound + + reference_velocity_magnitude = ( + reference_mach * thermal_state.speed_of_sound if reference_mach else None + ) + + log.info( + """Density and viscosity were calculated based on input data, ThermalState will be automatically created.""" + ) + + # pylint: disable=no-value-for-parameter + return cls( + velocity_magnitude=velocity_magnitude, + alpha=alpha, + beta=beta, + thermal_state=thermal_state, + reference_velocity_magnitude=reference_velocity_magnitude, + ) + @pd.model_validator(mode="after") @context_validator(context=CASE) def check_valid_reference_velocity(self) -> Self: @@ -471,99 +570,3 @@ def check_valid_reference_velocity(self) -> Self: OperatingConditionTypes = Union[ GenericReferenceCondition, AerospaceCondition, LiquidOperatingCondition ] - - -# pylint: disable=too-many-arguments -@pd.validate_call -def operating_condition_from_mach_reynolds( - mach: pd.NonNegativeFloat, - reynolds: pd.PositiveFloat, - project_length_unit: LengthType.Positive = pd.Field( - description="The Length unit of the project." - ), - temperature: AbsoluteTemperatureType = 288.15 * u.K, - alpha: Optional[AngleType] = 0 * u.deg, - beta: Optional[AngleType] = 0 * u.deg, - reference_mach: Optional[pd.PositiveFloat] = None, -) -> AerospaceCondition: - """ - Create an `AerospaceCondition` from Mach number and Reynolds number. - - This function computes the thermal state based on the given Mach number, - Reynolds number, and temperature, and returns an `AerospaceCondition` object - initialized with the computed thermal state and given aerodynamic angles. - - Parameters - ---------- - mach : NonNegativeFloat - Freestream Mach number (must be non-negative). - reynolds : PositiveFloat - Freestream Reynolds number defined with mesh unit (must be positive). - project_length_unit: LengthType.Positive - Project length unit. - temperature : AbsoluteTemperatureType, optional - Freestream static temperature (must be a positive temperature value). Default is 288.15 Kelvin. - alpha : AngleType, optional - Angle of attack. Default is 0 degrees. - beta : AngleType, optional - Sideslip angle. Default is 0 degrees. - reference_mach : PositiveFloat, optional - Reference Mach number. Default is None. - - Returns - ------- - AerospaceCondition - An `AerospaceCondition` object initialized with the given parameters. - - Raises - ------ - ValidationError - If the input values do not meet the specified constraints. - ValueError - If required parameters are missing or calculations cannot be performed. - - Example - ------- - Example usage: - - >>> condition = operating_condition_from_mach_reynolds( - ... mach=0.85, - ... reynolds=1e6, - ... project_length_unit=1 * u.mm, - ... temperature=288.15 * u.K, - ... alpha=2.0 * u.deg, - ... beta=0.0 * u.deg, - ... reference_mach=0.85, - ... ) - >>> print(condition) - AerospaceCondition(...) - - """ - - if temperature.units is u.K and temperature.value == 288.15: - log.info("Default value of 288.15 K will be used as temperature.") - - material = Air() - - velocity = (mach if reference_mach is None else reference_mach) * material.get_speed_of_sound( - temperature - ) - - density = ( - reynolds * material.get_dynamic_viscosity(temperature) / (velocity * project_length_unit) - ) - - thermal_state = ThermalState(temperature=temperature, density=density) - - log.info( - """Density and viscosity were calculated based on input data, ThermalState will be automatically created.""" - ) - - # pylint: disable=no-value-for-parameter - return AerospaceCondition.from_mach( - mach=mach, - alpha=alpha, - beta=beta, - thermal_state=thermal_state, - reference_mach=reference_mach, - ) diff --git a/tests/simulation/framework/test_multi_constructor_model.py b/tests/simulation/framework/test_multi_constructor_model.py index a6c9db934..befba71eb 100644 --- a/tests/simulation/framework/test_multi_constructor_model.py +++ b/tests/simulation/framework/test_multi_constructor_model.py @@ -42,7 +42,7 @@ def get_aerospace_condition_default_and_thermal_state_using_from(): @pytest.fixture -def get_aerospace_condition_using_from(): +def get_aerospace_condition_using_from_mach(): return AerospaceCondition.from_mach( mach=0.8, alpha=5 * u.deg, @@ -50,19 +50,34 @@ def get_aerospace_condition_using_from(): ) -def test_full_model(get_aerospace_condition_default, get_aerospace_condition_using_from): +@pytest.fixture +def get_aerospace_condition_using_from_mach_reynolds(): + return AerospaceCondition.from_mach_reynolds( + mach=0.8, + reynolds=1e+6, + project_length_unit=u.m, + alpha=5 * u.deg, + temperature=290 * u.K, + ) + + +def test_full_model(get_aerospace_condition_default, get_aerospace_condition_using_from_mach, get_aerospace_condition_using_from_mach_reynolds): full_data = get_aerospace_condition_default.model_dump(exclude_none=True) data_parsed = parse_model_dict(full_data, globals()) assert sorted(data_parsed.items()) == sorted(full_data.items()) - full_data = get_aerospace_condition_using_from.model_dump(exclude_none=True) + full_data = get_aerospace_condition_using_from_mach.model_dump(exclude_none=True) data_parsed = parse_model_dict(full_data, globals()) assert sorted(data_parsed.items()) == sorted(full_data.items()) + full_data = get_aerospace_condition_using_from_mach_reynolds.model_dump(exclude_none=True) + data_parsed = parse_model_dict(full_data, globals()) + assert sorted(data_parsed.items()) == sorted(full_data.items()) def test_incomplete_model( get_aerospace_condition_default, - get_aerospace_condition_using_from, + get_aerospace_condition_using_from_mach, + get_aerospace_condition_using_from_mach_reynolds, get_aerospace_condition_default_and_thermal_state_using_from, ): full_data = get_aerospace_condition_default.model_dump(exclude_none=True) @@ -73,7 +88,7 @@ def test_incomplete_model( assert sorted(data_parsed.items()) == sorted(full_data.items()) - full_data = get_aerospace_condition_using_from.model_dump(exclude_none=True) + full_data = get_aerospace_condition_using_from_mach.model_dump(exclude_none=True) incomplete_data = { "type_name": full_data["type_name"], "private_attribute_constructor": full_data["private_attribute_constructor"], @@ -82,6 +97,20 @@ def test_incomplete_model( data_parsed = parse_model_dict(incomplete_data, globals()) assert sorted(data_parsed.items()) == sorted(full_data.items()) + print(data_parsed) + + + full_data = get_aerospace_condition_using_from_mach_reynolds.model_dump(exclude_none=True) + incomplete_data = { + "type_name": full_data["type_name"], + "private_attribute_constructor": full_data["private_attribute_constructor"], + "private_attribute_input_cache": full_data["private_attribute_input_cache"], + } + + data_parsed = parse_model_dict(incomplete_data, globals()) + assert sorted(data_parsed.items()) == sorted(full_data.items()) + # print(data_parsed) + full_data = get_aerospace_condition_default_and_thermal_state_using_from.model_dump( exclude_none=True @@ -101,9 +130,9 @@ def test_incomplete_model( assert sorted(data_parsed.items()) == sorted(full_data.items()) -def test_recursive_incomplete_model(get_aerospace_condition_using_from): +def test_recursive_incomplete_model(get_aerospace_condition_using_from_mach): # `incomplete_data` contains only the private_attribute_* for both the AerospaceCondition and ThermalState - full_data = get_aerospace_condition_using_from.model_dump(exclude_none=True) + full_data = get_aerospace_condition_using_from_mach.model_dump(exclude_none=True) input_cache = full_data["private_attribute_input_cache"] input_cache["thermal_state"] = { "type_name": input_cache["thermal_state"]["type_name"], @@ -180,7 +209,7 @@ class ModelWithEntityList(Flow360BaseModel): assert sorted(data_parsed.items()) == sorted(full_data.items()) -def test_entity_modification(get_aerospace_condition_using_from): +def test_entity_modification(get_aerospace_condition_using_from_mach): my_box = Box.from_principal_axes( name="box", @@ -203,7 +232,7 @@ def test_entity_modification(get_aerospace_condition_using_from): my_box.size = (1, 2, 32) * u.m assert all(my_box.private_attribute_input_cache.size == (1, 2, 32) * u.m) - my_op = get_aerospace_condition_using_from + my_op = get_aerospace_condition_using_from_mach my_op.alpha = -12 * u.rad assert my_op.private_attribute_input_cache.alpha == -12 * u.rad diff --git a/tests/simulation/params/test_simulation_params.py b/tests/simulation/params/test_simulation_params.py index 2de606a09..869216f14 100644 --- a/tests/simulation/params/test_simulation_params.py +++ b/tests/simulation/params/test_simulation_params.py @@ -45,7 +45,6 @@ AerospaceCondition, LiquidOperatingCondition, ThermalState, - operating_condition_from_mach_reynolds, ) from flow360.component.simulation.primitives import ( Box, @@ -344,7 +343,7 @@ def test_subsequent_param_with_different_unit_system(): def test_mach_reynolds_op_cond(): - condition = operating_condition_from_mach_reynolds( + condition = AerospaceCondition.from_mach_reynolds( mach=0.2, reynolds=5e6, temperature=288.15 * u.K, @@ -355,7 +354,7 @@ def test_mach_reynolds_op_cond(): assertions.assertAlmostEqual(condition.thermal_state.dynamic_viscosity.value, 1.78929763e-5) assertions.assertAlmostEqual(condition.thermal_state.density.value, 1.31452332) - condition = operating_condition_from_mach_reynolds( + condition = AerospaceCondition.from_mach_reynolds( mach=0.2, reynolds=5e6, temperature=288.15 * u.K, @@ -367,7 +366,7 @@ def test_mach_reynolds_op_cond(): assertions.assertAlmostEqual(condition.thermal_state.density.value, 0.6572616596801923) with pytest.raises(ValueError, match="Input should be greater than 0"): - condition = operating_condition_from_mach_reynolds( + condition = AerospaceCondition.from_mach_reynolds( mach=0.2, reynolds=0, temperature=288.15 * u.K, diff --git a/tests/simulation/translator/utils/tutorial_2dcrm_param_generator.py b/tests/simulation/translator/utils/tutorial_2dcrm_param_generator.py index 31d130687..508d81098 100644 --- a/tests/simulation/translator/utils/tutorial_2dcrm_param_generator.py +++ b/tests/simulation/translator/utils/tutorial_2dcrm_param_generator.py @@ -7,7 +7,7 @@ Wall, ) from flow360.component.simulation.operating_condition.operating_condition import ( - operating_condition_from_mach_reynolds, + AerospaceCondition, ) from flow360.component.simulation.primitives import ReferenceGeometry, Surface from flow360.component.simulation.simulation_params import SimulationParams @@ -24,7 +24,7 @@ def get_2dcrm_tutorial_param(): reference_geometry=ReferenceGeometry( moment_center=[0.25, 0.005, 0], moment_length=[1, 1, 1], area=0.01 ), - operating_condition=operating_condition_from_mach_reynolds( + operating_condition=AerospaceCondition.from_mach_reynolds( mach=0.2, reynolds=5e6, temperature=272.1 * u.K, @@ -52,7 +52,7 @@ def get_2dcrm_tutorial_param_deg_c(): reference_geometry=ReferenceGeometry( moment_center=[0.25, 0.005, 0], moment_length=[1, 1, 1], area=0.01 ), - operating_condition=operating_condition_from_mach_reynolds( + operating_condition=AerospaceCondition.from_mach_reynolds( mach=0.2, reynolds=5e6, temperature=-1.05 * u.degC, @@ -80,7 +80,7 @@ def get_2dcrm_tutorial_param_deg_f(): reference_geometry=ReferenceGeometry( moment_center=[0.25, 0.005, 0], moment_length=[1, 1, 1], area=0.01 ), - operating_condition=operating_condition_from_mach_reynolds( + operating_condition=AerospaceCondition.from_mach_reynolds( mach=0.2, reynolds=5e6, temperature=30.11 * u.degF, From 249f29bbae52fe3af73bf77d2d3bebaed682c6d2 Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Thu, 24 Apr 2025 16:14:46 +0200 Subject: [PATCH 02/19] black and isort --- .../framework/test_multi_constructor_model.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/simulation/framework/test_multi_constructor_model.py b/tests/simulation/framework/test_multi_constructor_model.py index befba71eb..79726540c 100644 --- a/tests/simulation/framework/test_multi_constructor_model.py +++ b/tests/simulation/framework/test_multi_constructor_model.py @@ -54,14 +54,18 @@ def get_aerospace_condition_using_from_mach(): def get_aerospace_condition_using_from_mach_reynolds(): return AerospaceCondition.from_mach_reynolds( mach=0.8, - reynolds=1e+6, + reynolds=1e6, project_length_unit=u.m, alpha=5 * u.deg, temperature=290 * u.K, ) -def test_full_model(get_aerospace_condition_default, get_aerospace_condition_using_from_mach, get_aerospace_condition_using_from_mach_reynolds): +def test_full_model( + get_aerospace_condition_default, + get_aerospace_condition_using_from_mach, + get_aerospace_condition_using_from_mach_reynolds, +): full_data = get_aerospace_condition_default.model_dump(exclude_none=True) data_parsed = parse_model_dict(full_data, globals()) assert sorted(data_parsed.items()) == sorted(full_data.items()) @@ -74,6 +78,7 @@ def test_full_model(get_aerospace_condition_default, get_aerospace_condition_usi data_parsed = parse_model_dict(full_data, globals()) assert sorted(data_parsed.items()) == sorted(full_data.items()) + def test_incomplete_model( get_aerospace_condition_default, get_aerospace_condition_using_from_mach, @@ -97,8 +102,6 @@ def test_incomplete_model( data_parsed = parse_model_dict(incomplete_data, globals()) assert sorted(data_parsed.items()) == sorted(full_data.items()) - print(data_parsed) - full_data = get_aerospace_condition_using_from_mach_reynolds.model_dump(exclude_none=True) incomplete_data = { @@ -109,8 +112,6 @@ def test_incomplete_model( data_parsed = parse_model_dict(incomplete_data, globals()) assert sorted(data_parsed.items()) == sorted(full_data.items()) - # print(data_parsed) - full_data = get_aerospace_condition_default_and_thermal_state_using_from.model_dump( exclude_none=True From 5ece895146d1b8453a25cd5bf9b25a4d58011901 Mon Sep 17 00:00:00 2001 From: Maciej Skarysz Date: Thu, 24 Apr 2025 19:09:05 +0200 Subject: [PATCH 03/19] made exclude_none default in model_dump --- .../component/simulation/framework/base_model.py | 14 ++++++++++++++ .../operating_condition/operating_condition.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/flow360/component/simulation/framework/base_model.py b/flow360/component/simulation/framework/base_model.py index f86889479..e58841489 100644 --- a/flow360/component/simulation/framework/base_model.py +++ b/flow360/component/simulation/framework/base_model.py @@ -483,6 +483,20 @@ def _to_json(self, filename: str, **kwargs) -> None: with open(filename, "w+", encoding="utf-8") as file_handle: json.dump(model_dict, file_handle, indent=4, sort_keys=True) + def model_dump(self, **kwargs) -> dict: + """Override of pydantic's model_dump to set exclude_none=True by default. + + Returns a dictionary representation of the model. + All None values will be excluded by default. + + Returns + ------- + dict + A dictionary of the model's fields and values. + """ + kwargs.setdefault('exclude_none', True) + return super().model_dump(**kwargs) + @classmethod def _dict_from_yaml(cls, filename: str) -> dict: """Load dictionary of the model from a .yaml file. diff --git a/flow360/component/simulation/operating_condition/operating_condition.py b/flow360/component/simulation/operating_condition/operating_condition.py index c401d5ddd..9a84dc8a7 100644 --- a/flow360/component/simulation/operating_condition/operating_condition.py +++ b/flow360/component/simulation/operating_condition/operating_condition.py @@ -244,7 +244,7 @@ class AerospaceConditionCache(Flow360BaseModel): """[INTERNAL] Cache for AerospaceCondition inputs""" mach: Optional[pd.NonNegativeFloat] = None - # reynolds: Optional[pd.PositiveFloat] = None + reynolds: Optional[pd.PositiveFloat] = None project_length_unit: Optional[LengthType.Positive] = None alpha: Optional[AngleType] = None beta: Optional[AngleType] = None From 4137165f63816608f6c6a8a40703ff7175159603 Mon Sep 17 00:00:00 2001 From: Maciej Skarysz Date: Thu, 24 Apr 2025 19:10:16 +0200 Subject: [PATCH 04/19] fixed test --- tests/simulation/converter/test_monitor_flow360_converter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/simulation/converter/test_monitor_flow360_converter.py b/tests/simulation/converter/test_monitor_flow360_converter.py index a98723833..3fed9d180 100644 --- a/tests/simulation/converter/test_monitor_flow360_converter.py +++ b/tests/simulation/converter/test_monitor_flow360_converter.py @@ -36,6 +36,7 @@ def test_flow360_monitor_convert(): params_dict = params.model_dump( mode="json", + exclude_none=False, exclude={ "type_name", "private_attribute_constructor", From 1140140060b9b1da0ad6f522a9781fc3093c79d3 Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Mon, 28 Apr 2025 18:35:26 +0200 Subject: [PATCH 05/19] fixed solver translator unittests --- flow360/component/simulation/framework/base_model.py | 6 +++--- tests/simulation/translator/test_solver_translator.py | 2 +- .../translator/utils/NestedCylindersSRF_param_generator.py | 5 ++++- .../translator/utils/XV15HoverMRF_param_generator.py | 5 ++++- .../translator/utils/symmetryBC_param_generator.py | 5 ++++- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/flow360/component/simulation/framework/base_model.py b/flow360/component/simulation/framework/base_model.py index e58841489..815287bea 100644 --- a/flow360/component/simulation/framework/base_model.py +++ b/flow360/component/simulation/framework/base_model.py @@ -485,16 +485,16 @@ def _to_json(self, filename: str, **kwargs) -> None: def model_dump(self, **kwargs) -> dict: """Override of pydantic's model_dump to set exclude_none=True by default. - + Returns a dictionary representation of the model. All None values will be excluded by default. - + Returns ------- dict A dictionary of the model's fields and values. """ - kwargs.setdefault('exclude_none', True) + kwargs.setdefault("exclude_none", True) return super().model_dump(**kwargs) @classmethod diff --git a/tests/simulation/translator/test_solver_translator.py b/tests/simulation/translator/test_solver_translator.py index eac407525..6a7c689e0 100644 --- a/tests/simulation/translator/test_solver_translator.py +++ b/tests/simulation/translator/test_solver_translator.py @@ -146,7 +146,7 @@ def get_om6Wing_tutorial_param(): SlipWall(entities=[my_symmetry_plane]), Freestream(entities=[my_freestream]), ], - time_stepping=Steady(CFL=RampCFL()), + time_stepping=Steady(CFL=RampCFL(final=200, initial=5, ramp_steps=40)), outputs=[ VolumeOutput( output_format="paraview", diff --git a/tests/simulation/translator/utils/NestedCylindersSRF_param_generator.py b/tests/simulation/translator/utils/NestedCylindersSRF_param_generator.py index 1a06f0554..f012a4baa 100644 --- a/tests/simulation/translator/utils/NestedCylindersSRF_param_generator.py +++ b/tests/simulation/translator/utils/NestedCylindersSRF_param_generator.py @@ -81,7 +81,10 @@ def create_NestedCylindersSRF_param(srf_cylinder): rotating_reference_frame_model=True, ), ], - time_stepping=Steady(CFL=AdaptiveCFL(), max_steps=2000), + time_stepping=Steady( + CFL=AdaptiveCFL(max=10000, max_relative_change=1, convergence_limiting_factor=0.25), + max_steps=2000, + ), outputs=[ VolumeOutput( output_format="paraview", diff --git a/tests/simulation/translator/utils/XV15HoverMRF_param_generator.py b/tests/simulation/translator/utils/XV15HoverMRF_param_generator.py index d020e44be..a5c6a6297 100644 --- a/tests/simulation/translator/utils/XV15HoverMRF_param_generator.py +++ b/tests/simulation/translator/utils/XV15HoverMRF_param_generator.py @@ -79,7 +79,10 @@ def create_XV15HoverMRF_param(rotation_cylinder): Freestream(entities=[my_freestream]), Rotation(entities=[rotation_cylinder], spec=AngularVelocity(600.106 * u.rpm)), ], - time_stepping=Steady(CFL=AdaptiveCFL(), max_steps=4000), + time_stepping=Steady( + CFL=AdaptiveCFL(max=10000, max_relative_change=1, convergence_limiting_factor=0.25), + max_steps=4000, + ), outputs=[ VolumeOutput( output_format="paraview", diff --git a/tests/simulation/translator/utils/symmetryBC_param_generator.py b/tests/simulation/translator/utils/symmetryBC_param_generator.py index ed2cf7713..da4eb1ea4 100644 --- a/tests/simulation/translator/utils/symmetryBC_param_generator.py +++ b/tests/simulation/translator/utils/symmetryBC_param_generator.py @@ -66,7 +66,10 @@ def create_symmetryBC_param(): SymmetryPlane(entities=[my_symmetry_plane]), Freestream(entities=[my_freestream]), ], - time_stepping=Steady(CFL=AdaptiveCFL(), max_steps=5000), + time_stepping=Steady( + CFL=AdaptiveCFL(max=10000, max_relative_change=1, convergence_limiting_factor=0.25), + max_steps=5000, + ), outputs=[ VolumeOutput( output_format="paraview", From cc5b6f0f2a169527ce375980d216789cd79a861a Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Wed, 30 Apr 2025 12:33:42 +0200 Subject: [PATCH 06/19] Revert "fixed solver translator unittests" This reverts commit 1140140060b9b1da0ad6f522a9781fc3093c79d3. --- flow360/component/simulation/framework/base_model.py | 6 +++--- tests/simulation/translator/test_solver_translator.py | 2 +- .../translator/utils/NestedCylindersSRF_param_generator.py | 5 +---- .../translator/utils/XV15HoverMRF_param_generator.py | 5 +---- .../translator/utils/symmetryBC_param_generator.py | 5 +---- 5 files changed, 7 insertions(+), 16 deletions(-) diff --git a/flow360/component/simulation/framework/base_model.py b/flow360/component/simulation/framework/base_model.py index 815287bea..e58841489 100644 --- a/flow360/component/simulation/framework/base_model.py +++ b/flow360/component/simulation/framework/base_model.py @@ -485,16 +485,16 @@ def _to_json(self, filename: str, **kwargs) -> None: def model_dump(self, **kwargs) -> dict: """Override of pydantic's model_dump to set exclude_none=True by default. - + Returns a dictionary representation of the model. All None values will be excluded by default. - + Returns ------- dict A dictionary of the model's fields and values. """ - kwargs.setdefault("exclude_none", True) + kwargs.setdefault('exclude_none', True) return super().model_dump(**kwargs) @classmethod diff --git a/tests/simulation/translator/test_solver_translator.py b/tests/simulation/translator/test_solver_translator.py index 6a7c689e0..eac407525 100644 --- a/tests/simulation/translator/test_solver_translator.py +++ b/tests/simulation/translator/test_solver_translator.py @@ -146,7 +146,7 @@ def get_om6Wing_tutorial_param(): SlipWall(entities=[my_symmetry_plane]), Freestream(entities=[my_freestream]), ], - time_stepping=Steady(CFL=RampCFL(final=200, initial=5, ramp_steps=40)), + time_stepping=Steady(CFL=RampCFL()), outputs=[ VolumeOutput( output_format="paraview", diff --git a/tests/simulation/translator/utils/NestedCylindersSRF_param_generator.py b/tests/simulation/translator/utils/NestedCylindersSRF_param_generator.py index f012a4baa..1a06f0554 100644 --- a/tests/simulation/translator/utils/NestedCylindersSRF_param_generator.py +++ b/tests/simulation/translator/utils/NestedCylindersSRF_param_generator.py @@ -81,10 +81,7 @@ def create_NestedCylindersSRF_param(srf_cylinder): rotating_reference_frame_model=True, ), ], - time_stepping=Steady( - CFL=AdaptiveCFL(max=10000, max_relative_change=1, convergence_limiting_factor=0.25), - max_steps=2000, - ), + time_stepping=Steady(CFL=AdaptiveCFL(), max_steps=2000), outputs=[ VolumeOutput( output_format="paraview", diff --git a/tests/simulation/translator/utils/XV15HoverMRF_param_generator.py b/tests/simulation/translator/utils/XV15HoverMRF_param_generator.py index a5c6a6297..d020e44be 100644 --- a/tests/simulation/translator/utils/XV15HoverMRF_param_generator.py +++ b/tests/simulation/translator/utils/XV15HoverMRF_param_generator.py @@ -79,10 +79,7 @@ def create_XV15HoverMRF_param(rotation_cylinder): Freestream(entities=[my_freestream]), Rotation(entities=[rotation_cylinder], spec=AngularVelocity(600.106 * u.rpm)), ], - time_stepping=Steady( - CFL=AdaptiveCFL(max=10000, max_relative_change=1, convergence_limiting_factor=0.25), - max_steps=4000, - ), + time_stepping=Steady(CFL=AdaptiveCFL(), max_steps=4000), outputs=[ VolumeOutput( output_format="paraview", diff --git a/tests/simulation/translator/utils/symmetryBC_param_generator.py b/tests/simulation/translator/utils/symmetryBC_param_generator.py index da4eb1ea4..ed2cf7713 100644 --- a/tests/simulation/translator/utils/symmetryBC_param_generator.py +++ b/tests/simulation/translator/utils/symmetryBC_param_generator.py @@ -66,10 +66,7 @@ def create_symmetryBC_param(): SymmetryPlane(entities=[my_symmetry_plane]), Freestream(entities=[my_freestream]), ], - time_stepping=Steady( - CFL=AdaptiveCFL(max=10000, max_relative_change=1, convergence_limiting_factor=0.25), - max_steps=5000, - ), + time_stepping=Steady(CFL=AdaptiveCFL(), max_steps=5000), outputs=[ VolumeOutput( output_format="paraview", From 8cf7dc1451164fa4f6e067c1dabdb4e86c0d5bc0 Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Wed, 30 Apr 2025 12:33:52 +0200 Subject: [PATCH 07/19] Revert "fixed test" This reverts commit 4137165f63816608f6c6a8a40703ff7175159603. --- tests/simulation/converter/test_monitor_flow360_converter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/simulation/converter/test_monitor_flow360_converter.py b/tests/simulation/converter/test_monitor_flow360_converter.py index 3fed9d180..a98723833 100644 --- a/tests/simulation/converter/test_monitor_flow360_converter.py +++ b/tests/simulation/converter/test_monitor_flow360_converter.py @@ -36,7 +36,6 @@ def test_flow360_monitor_convert(): params_dict = params.model_dump( mode="json", - exclude_none=False, exclude={ "type_name", "private_attribute_constructor", From 6f2d7cce9c386c5f278f4202eac5e7fef93c072a Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Wed, 30 Apr 2025 12:34:01 +0200 Subject: [PATCH 08/19] Revert "made exclude_none default in model_dump" This reverts commit 5ece895146d1b8453a25cd5bf9b25a4d58011901. --- .../component/simulation/framework/base_model.py | 14 -------------- .../operating_condition/operating_condition.py | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/flow360/component/simulation/framework/base_model.py b/flow360/component/simulation/framework/base_model.py index e58841489..f86889479 100644 --- a/flow360/component/simulation/framework/base_model.py +++ b/flow360/component/simulation/framework/base_model.py @@ -483,20 +483,6 @@ def _to_json(self, filename: str, **kwargs) -> None: with open(filename, "w+", encoding="utf-8") as file_handle: json.dump(model_dict, file_handle, indent=4, sort_keys=True) - def model_dump(self, **kwargs) -> dict: - """Override of pydantic's model_dump to set exclude_none=True by default. - - Returns a dictionary representation of the model. - All None values will be excluded by default. - - Returns - ------- - dict - A dictionary of the model's fields and values. - """ - kwargs.setdefault('exclude_none', True) - return super().model_dump(**kwargs) - @classmethod def _dict_from_yaml(cls, filename: str) -> dict: """Load dictionary of the model from a .yaml file. diff --git a/flow360/component/simulation/operating_condition/operating_condition.py b/flow360/component/simulation/operating_condition/operating_condition.py index 9a84dc8a7..c401d5ddd 100644 --- a/flow360/component/simulation/operating_condition/operating_condition.py +++ b/flow360/component/simulation/operating_condition/operating_condition.py @@ -244,7 +244,7 @@ class AerospaceConditionCache(Flow360BaseModel): """[INTERNAL] Cache for AerospaceCondition inputs""" mach: Optional[pd.NonNegativeFloat] = None - reynolds: Optional[pd.PositiveFloat] = None + # reynolds: Optional[pd.PositiveFloat] = None project_length_unit: Optional[LengthType.Positive] = None alpha: Optional[AngleType] = None beta: Optional[AngleType] = None From bae5e3d7b888784f6983da8603e15869921ab02a Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Wed, 30 Apr 2025 16:25:12 +0200 Subject: [PATCH 09/19] added removing none fields for multi constructor model --- .../simulation/framework/multi_constructor_model_base.py | 3 +++ .../simulation/operating_condition/operating_condition.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/flow360/component/simulation/framework/multi_constructor_model_base.py b/flow360/component/simulation/framework/multi_constructor_model_base.py index f0687d93c..1b7495c88 100644 --- a/flow360/component/simulation/framework/multi_constructor_model_base.py +++ b/flow360/component/simulation/framework/multi_constructor_model_base.py @@ -183,6 +183,9 @@ def model_custom_constructor_parser(model_as_dict, global_vars): if constructor_name != "default": constructor = get_class_method(model_cls, constructor_name) try: + for i in list(input_kwargs): + if input_kwargs[i] == None: + input_kwargs.pop(i) return constructor(**(input_kwargs | id_kwarg)).model_dump(exclude_none=True) except pd.ValidationError as err: # pylint:disable = raise-missing-from diff --git a/flow360/component/simulation/operating_condition/operating_condition.py b/flow360/component/simulation/operating_condition/operating_condition.py index c401d5ddd..9a84dc8a7 100644 --- a/flow360/component/simulation/operating_condition/operating_condition.py +++ b/flow360/component/simulation/operating_condition/operating_condition.py @@ -244,7 +244,7 @@ class AerospaceConditionCache(Flow360BaseModel): """[INTERNAL] Cache for AerospaceCondition inputs""" mach: Optional[pd.NonNegativeFloat] = None - # reynolds: Optional[pd.PositiveFloat] = None + reynolds: Optional[pd.PositiveFloat] = None project_length_unit: Optional[LengthType.Positive] = None alpha: Optional[AngleType] = None beta: Optional[AngleType] = None From 38358f9d67360d1919e2a663e6ff5c593cb0202f Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Wed, 30 Apr 2025 16:29:07 +0200 Subject: [PATCH 10/19] small function name change to be more clear --- tests/simulation/framework/test_multi_constructor_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/simulation/framework/test_multi_constructor_model.py b/tests/simulation/framework/test_multi_constructor_model.py index 79726540c..e69693c4c 100644 --- a/tests/simulation/framework/test_multi_constructor_model.py +++ b/tests/simulation/framework/test_multi_constructor_model.py @@ -32,7 +32,7 @@ def get_aerospace_condition_default(): @pytest.fixture -def get_aerospace_condition_default_and_thermal_state_using_from(): +def get_aerospace_condition_default_and_thermal_state_using_from_mach(): return AerospaceCondition( velocity_magnitude=0.8 * u.km / u.s, alpha=5 * u.deg, @@ -83,7 +83,7 @@ def test_incomplete_model( get_aerospace_condition_default, get_aerospace_condition_using_from_mach, get_aerospace_condition_using_from_mach_reynolds, - get_aerospace_condition_default_and_thermal_state_using_from, + get_aerospace_condition_default_and_thermal_state_using_from_mach, ): full_data = get_aerospace_condition_default.model_dump(exclude_none=True) @@ -113,7 +113,7 @@ def test_incomplete_model( data_parsed = parse_model_dict(incomplete_data, globals()) assert sorted(data_parsed.items()) == sorted(full_data.items()) - full_data = get_aerospace_condition_default_and_thermal_state_using_from.model_dump( + full_data = get_aerospace_condition_default_and_thermal_state_using_from_mach.model_dump( exclude_none=True ) incomplete_data = deepcopy(full_data) From 71dff8c0815670e2152b3da790d0b7b12b9066a1 Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Wed, 30 Apr 2025 16:34:11 +0200 Subject: [PATCH 11/19] Revert "small function name change to be more clear" This reverts commit 38358f9d67360d1919e2a663e6ff5c593cb0202f. --- tests/simulation/framework/test_multi_constructor_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/simulation/framework/test_multi_constructor_model.py b/tests/simulation/framework/test_multi_constructor_model.py index e69693c4c..79726540c 100644 --- a/tests/simulation/framework/test_multi_constructor_model.py +++ b/tests/simulation/framework/test_multi_constructor_model.py @@ -32,7 +32,7 @@ def get_aerospace_condition_default(): @pytest.fixture -def get_aerospace_condition_default_and_thermal_state_using_from_mach(): +def get_aerospace_condition_default_and_thermal_state_using_from(): return AerospaceCondition( velocity_magnitude=0.8 * u.km / u.s, alpha=5 * u.deg, @@ -83,7 +83,7 @@ def test_incomplete_model( get_aerospace_condition_default, get_aerospace_condition_using_from_mach, get_aerospace_condition_using_from_mach_reynolds, - get_aerospace_condition_default_and_thermal_state_using_from_mach, + get_aerospace_condition_default_and_thermal_state_using_from, ): full_data = get_aerospace_condition_default.model_dump(exclude_none=True) @@ -113,7 +113,7 @@ def test_incomplete_model( data_parsed = parse_model_dict(incomplete_data, globals()) assert sorted(data_parsed.items()) == sorted(full_data.items()) - full_data = get_aerospace_condition_default_and_thermal_state_using_from_mach.model_dump( + full_data = get_aerospace_condition_default_and_thermal_state_using_from.model_dump( exclude_none=True ) incomplete_data = deepcopy(full_data) From 509f703089eef5e4197df2b9ff4b8d34db5096ae Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Wed, 30 Apr 2025 16:34:42 +0200 Subject: [PATCH 12/19] Revert "added removing none fields for multi constructor model" This reverts commit bae5e3d7b888784f6983da8603e15869921ab02a. --- .../simulation/framework/multi_constructor_model_base.py | 3 --- .../simulation/operating_condition/operating_condition.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/flow360/component/simulation/framework/multi_constructor_model_base.py b/flow360/component/simulation/framework/multi_constructor_model_base.py index 1b7495c88..f0687d93c 100644 --- a/flow360/component/simulation/framework/multi_constructor_model_base.py +++ b/flow360/component/simulation/framework/multi_constructor_model_base.py @@ -183,9 +183,6 @@ def model_custom_constructor_parser(model_as_dict, global_vars): if constructor_name != "default": constructor = get_class_method(model_cls, constructor_name) try: - for i in list(input_kwargs): - if input_kwargs[i] == None: - input_kwargs.pop(i) return constructor(**(input_kwargs | id_kwarg)).model_dump(exclude_none=True) except pd.ValidationError as err: # pylint:disable = raise-missing-from diff --git a/flow360/component/simulation/operating_condition/operating_condition.py b/flow360/component/simulation/operating_condition/operating_condition.py index 9a84dc8a7..c401d5ddd 100644 --- a/flow360/component/simulation/operating_condition/operating_condition.py +++ b/flow360/component/simulation/operating_condition/operating_condition.py @@ -244,7 +244,7 @@ class AerospaceConditionCache(Flow360BaseModel): """[INTERNAL] Cache for AerospaceCondition inputs""" mach: Optional[pd.NonNegativeFloat] = None - reynolds: Optional[pd.PositiveFloat] = None + # reynolds: Optional[pd.PositiveFloat] = None project_length_unit: Optional[LengthType.Positive] = None alpha: Optional[AngleType] = None beta: Optional[AngleType] = None From cbaec5dbafbbbbb23f0ac636f53d1357890d7594 Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Wed, 30 Apr 2025 16:54:03 +0200 Subject: [PATCH 13/19] fixed conflicts in unittest --- .../operating_condition.py | 2 +- .../framework/test_multi_constructor_model.py | 55 ++++++++++--------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/flow360/component/simulation/operating_condition/operating_condition.py b/flow360/component/simulation/operating_condition/operating_condition.py index c401d5ddd..9a84dc8a7 100644 --- a/flow360/component/simulation/operating_condition/operating_condition.py +++ b/flow360/component/simulation/operating_condition/operating_condition.py @@ -244,7 +244,7 @@ class AerospaceConditionCache(Flow360BaseModel): """[INTERNAL] Cache for AerospaceCondition inputs""" mach: Optional[pd.NonNegativeFloat] = None - # reynolds: Optional[pd.PositiveFloat] = None + reynolds: Optional[pd.PositiveFloat] = None project_length_unit: Optional[LengthType.Positive] = None alpha: Optional[AngleType] = None beta: Optional[AngleType] = None diff --git a/tests/simulation/framework/test_multi_constructor_model.py b/tests/simulation/framework/test_multi_constructor_model.py index 79726540c..179474e9b 100644 --- a/tests/simulation/framework/test_multi_constructor_model.py +++ b/tests/simulation/framework/test_multi_constructor_model.py @@ -61,22 +61,28 @@ def get_aerospace_condition_using_from_mach_reynolds(): ) +def compare_objects_from_dict(dict1: dict, dict2: dict, object_class: type[Flow360BaseModel]): + obj1 = object_class.model_validate(dict1) + obj2 = object_class.model_validate(dict2) + assert obj1.model_dump_json() == obj2.model_dump_json() + + def test_full_model( get_aerospace_condition_default, get_aerospace_condition_using_from_mach, get_aerospace_condition_using_from_mach_reynolds, ): - full_data = get_aerospace_condition_default.model_dump(exclude_none=True) + full_data = get_aerospace_condition_default.model_dump(exclude_none=False) data_parsed = parse_model_dict(full_data, globals()) - assert sorted(data_parsed.items()) == sorted(full_data.items()) + compare_objects_from_dict(full_data, data_parsed, AerospaceCondition) - full_data = get_aerospace_condition_using_from_mach.model_dump(exclude_none=True) + full_data = get_aerospace_condition_using_from_mach.model_dump(exclude_none=False) data_parsed = parse_model_dict(full_data, globals()) - assert sorted(data_parsed.items()) == sorted(full_data.items()) + compare_objects_from_dict(full_data, data_parsed, AerospaceCondition) - full_data = get_aerospace_condition_using_from_mach_reynolds.model_dump(exclude_none=True) + full_data = get_aerospace_condition_using_from_mach_reynolds.model_dump(exclude_none=False) data_parsed = parse_model_dict(full_data, globals()) - assert sorted(data_parsed.items()) == sorted(full_data.items()) + compare_objects_from_dict(full_data, data_parsed, AerospaceCondition) def test_incomplete_model( @@ -85,15 +91,14 @@ def test_incomplete_model( get_aerospace_condition_using_from_mach_reynolds, get_aerospace_condition_default_and_thermal_state_using_from, ): - full_data = get_aerospace_condition_default.model_dump(exclude_none=True) + full_data = get_aerospace_condition_default.model_dump(exclude_none=False) - incomplete_data = full_data - incomplete_data["private_attribute_input_cache"] = None + incomplete_data = deepcopy(full_data) + incomplete_data["private_attribute_input_cache"] = {} data_parsed = parse_model_dict(incomplete_data, globals()) + compare_objects_from_dict(full_data, data_parsed, AerospaceCondition) - assert sorted(data_parsed.items()) == sorted(full_data.items()) - - full_data = get_aerospace_condition_using_from_mach.model_dump(exclude_none=True) + full_data = get_aerospace_condition_using_from_mach.model_dump(exclude_none=False) incomplete_data = { "type_name": full_data["type_name"], "private_attribute_constructor": full_data["private_attribute_constructor"], @@ -101,9 +106,9 @@ def test_incomplete_model( } data_parsed = parse_model_dict(incomplete_data, globals()) - assert sorted(data_parsed.items()) == sorted(full_data.items()) + compare_objects_from_dict(full_data, data_parsed, AerospaceCondition) - full_data = get_aerospace_condition_using_from_mach_reynolds.model_dump(exclude_none=True) + full_data = get_aerospace_condition_using_from_mach_reynolds.model_dump(exclude_none=False) incomplete_data = { "type_name": full_data["type_name"], "private_attribute_constructor": full_data["private_attribute_constructor"], @@ -111,10 +116,10 @@ def test_incomplete_model( } data_parsed = parse_model_dict(incomplete_data, globals()) - assert sorted(data_parsed.items()) == sorted(full_data.items()) + compare_objects_from_dict(full_data, data_parsed, AerospaceCondition) full_data = get_aerospace_condition_default_and_thermal_state_using_from.model_dump( - exclude_none=True + exclude_none=False ) incomplete_data = deepcopy(full_data) incomplete_data["thermal_state"] = { @@ -128,12 +133,12 @@ def test_incomplete_model( } data_parsed = parse_model_dict(incomplete_data, globals()) - assert sorted(data_parsed.items()) == sorted(full_data.items()) + compare_objects_from_dict(full_data, data_parsed, AerospaceCondition) def test_recursive_incomplete_model(get_aerospace_condition_using_from_mach): # `incomplete_data` contains only the private_attribute_* for both the AerospaceCondition and ThermalState - full_data = get_aerospace_condition_using_from_mach.model_dump(exclude_none=True) + full_data = get_aerospace_condition_using_from_mach.model_dump(exclude_none=False) input_cache = full_data["private_attribute_input_cache"] input_cache["thermal_state"] = { "type_name": input_cache["thermal_state"]["type_name"], @@ -151,7 +156,7 @@ def test_recursive_incomplete_model(get_aerospace_condition_using_from_mach): } data_parsed = parse_model_dict(incomplete_data, globals()) - assert sorted(data_parsed.items()) == sorted(full_data.items()) + compare_objects_from_dict(full_data, data_parsed, AerospaceCondition) def test_entity_with_multi_constructor(): @@ -184,7 +189,7 @@ class ModelWithEntityList(Flow360BaseModel): ), ] ) - full_data = model.model_dump(exclude_none=True) + full_data = model.model_dump(exclude_none=False) incomplete_data = {"entities": {"stored_entities": []}} # For default constructed entity we do not do anything incomplete_data["entities"]["stored_entities"].append( @@ -207,7 +212,7 @@ class ModelWithEntityList(Flow360BaseModel): ) data_parsed = parse_model_dict(incomplete_data, globals()) - assert sorted(data_parsed.items()) == sorted(full_data.items()) + compare_objects_from_dict(full_data, data_parsed, ModelWithEntityList) def test_entity_modification(get_aerospace_condition_using_from_mach): @@ -241,9 +246,9 @@ def test_entity_modification(get_aerospace_condition_using_from_mach): def test_BETDisk_multi_constructor_full(): for bet_type in ["c81", "dfdc", "xfoil", "xrotor"]: bet = generate_BET_param(bet_type) - full_data = bet.model_dump(exclude_none=True) + full_data = bet.model_dump(exclude_none=False) data_parsed = parse_model_dict(full_data, globals()) - assert sorted(data_parsed.items()) == sorted(full_data.items()) + compare_objects_from_dict(full_data, data_parsed, BETDisk) def test_BETDisk_multi_constructor_cache_only(): @@ -257,7 +262,7 @@ def test_BETDisk_multi_constructor_cache_only(): # Ooops I changed my directory (trying using the json in some other folder) os.chdir(original_workdir) - full_data = bet.model_dump(exclude_none=True) + full_data = bet.model_dump(exclude_none=False) incomplete_data = { "type_name": full_data["type_name"], "private_attribute_constructor": full_data["private_attribute_constructor"], @@ -266,4 +271,4 @@ def test_BETDisk_multi_constructor_cache_only(): # Make sure cache only can be deserialized and that we won't have # trouble even if we switch directory where the file path no longer is valid. data_parsed = parse_model_dict(incomplete_data, globals()) - assert sorted(data_parsed.items()) == sorted(full_data.items()) + compare_objects_from_dict(full_data, data_parsed, BETDisk) From d8fd481aabeb766b731e17b5bce7108210c3e0ea Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Wed, 30 Apr 2025 16:59:03 +0200 Subject: [PATCH 14/19] black --- tests/simulation/framework/test_multi_constructor_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/simulation/framework/test_multi_constructor_model.py b/tests/simulation/framework/test_multi_constructor_model.py index 179474e9b..5b5759ecf 100644 --- a/tests/simulation/framework/test_multi_constructor_model.py +++ b/tests/simulation/framework/test_multi_constructor_model.py @@ -62,9 +62,9 @@ def get_aerospace_condition_using_from_mach_reynolds(): def compare_objects_from_dict(dict1: dict, dict2: dict, object_class: type[Flow360BaseModel]): - obj1 = object_class.model_validate(dict1) - obj2 = object_class.model_validate(dict2) - assert obj1.model_dump_json() == obj2.model_dump_json() + obj1 = object_class.model_validate(dict1) + obj2 = object_class.model_validate(dict2) + assert obj1.model_dump_json() == obj2.model_dump_json() def test_full_model( From dd9f0dc4205cf3e25d8148452113588b623f618b Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Wed, 30 Apr 2025 17:01:35 +0200 Subject: [PATCH 15/19] removed space for consistency --- tests/simulation/framework/test_multi_constructor_model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/simulation/framework/test_multi_constructor_model.py b/tests/simulation/framework/test_multi_constructor_model.py index 5b5759ecf..2b5670119 100644 --- a/tests/simulation/framework/test_multi_constructor_model.py +++ b/tests/simulation/framework/test_multi_constructor_model.py @@ -92,7 +92,6 @@ def test_incomplete_model( get_aerospace_condition_default_and_thermal_state_using_from, ): full_data = get_aerospace_condition_default.model_dump(exclude_none=False) - incomplete_data = deepcopy(full_data) incomplete_data["private_attribute_input_cache"] = {} data_parsed = parse_model_dict(incomplete_data, globals()) From 161b7ae75b7bc21fee426322b7da78ca67159435 Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Fri, 16 May 2025 16:06:51 +0200 Subject: [PATCH 16/19] changed density to be calculated from mach and not mach ref --- .../simulation/operating_condition/operating_condition.py | 4 +--- tests/simulation/params/test_simulation_params.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/flow360/component/simulation/operating_condition/operating_condition.py b/flow360/component/simulation/operating_condition/operating_condition.py index 9a84dc8a7..ab7f91a32 100644 --- a/flow360/component/simulation/operating_condition/operating_condition.py +++ b/flow360/component/simulation/operating_condition/operating_condition.py @@ -438,9 +438,7 @@ def from_mach_reynolds( material = Air() - velocity = ( - mach if reference_mach is None else reference_mach - ) * material.get_speed_of_sound(temperature) + velocity = mach * material.get_speed_of_sound(temperature) density = ( reynolds diff --git a/tests/simulation/params/test_simulation_params.py b/tests/simulation/params/test_simulation_params.py index 91362027e..b2905971a 100644 --- a/tests/simulation/params/test_simulation_params.py +++ b/tests/simulation/params/test_simulation_params.py @@ -364,7 +364,7 @@ def test_mach_reynolds_op_cond(): project_length_unit=u.m, reference_mach=0.4, ) - assertions.assertAlmostEqual(condition.thermal_state.density.value, 0.6572616596801923) + assertions.assertAlmostEqual(condition.thermal_state.density.value, 1.31452332) with pytest.raises(ValueError, match="Input should be greater than 0"): condition = AerospaceCondition.from_mach_reynolds( From e33c0f0b98b9b2419b4684d12ea54cc8f8dfd0a9 Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Fri, 16 May 2025 21:55:03 +0200 Subject: [PATCH 17/19] changed reynolds number function to be consistent with solver --- .../operating_condition/operating_condition.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/flow360/component/simulation/operating_condition/operating_condition.py b/flow360/component/simulation/operating_condition/operating_condition.py index ab7f91a32..71c21f06e 100644 --- a/flow360/component/simulation/operating_condition/operating_condition.py +++ b/flow360/component/simulation/operating_condition/operating_condition.py @@ -378,7 +378,7 @@ def from_mach( @pd.validate_call def from_mach_reynolds( cls, - mach: pd.NonNegativeFloat, + mach: pd.PositiveFloat, reynolds: pd.PositiveFloat, project_length_unit: LengthType.Positive, alpha: Optional[AngleType] = 0 * u.deg, @@ -496,10 +496,9 @@ def _update_input_cache(cls, value, info: pd.ValidationInfo): def flow360_reynolds_number(self, length_unit: LengthType.Positive): """ Computes length_unit based Reynolds number. - :math:`Re = \\rho_{\\infty} \\cdot U_{ref} \\cdot L_{grid}/\\mu_{\\infty}` where - - :math:`rho_{\\infty}` is the freestream fluid density. - - :math:`U_{ref}` is the reference velocity magnitude or freestream velocity magnitude if reference - velocity magnitude is not set. + :math:`Re = \\rho_{\\infty} \\cdot U_{infty} \\cdot L_{grid}/\\mu_{\\infty}` where + - :math:`\\rho_{\\infty}` is the freestream fluid density. + - :math:`U_{infty}` is the freestream velocity magnitude. - :math:`L_{grid}` is physical length represented by unit length in the given mesh/geometry file. - :math:`\\mu_{\\infty}` is the dynamic eddy viscosity of the fluid of freestream. @@ -508,14 +507,10 @@ def flow360_reynolds_number(self, length_unit: LengthType.Positive): length_unit : LengthType.Positive Physical length represented by unit length in the given mesh/geometry file. """ - reference_velocity = ( - self.reference_velocity_magnitude - if self.reference_velocity_magnitude - else self.velocity_magnitude - ) + return ( self.thermal_state.density - * reference_velocity + * self.velocity_magnitude * length_unit / self.thermal_state.dynamic_viscosity ).value From f66b0ae0b44331cc003b43d2eeb02e8bc4705613 Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Fri, 16 May 2025 21:56:56 +0200 Subject: [PATCH 18/19] added empty line so that list builds correctly --- .../simulation/operating_condition/operating_condition.py | 1 + 1 file changed, 1 insertion(+) diff --git a/flow360/component/simulation/operating_condition/operating_condition.py b/flow360/component/simulation/operating_condition/operating_condition.py index 71c21f06e..368eb515b 100644 --- a/flow360/component/simulation/operating_condition/operating_condition.py +++ b/flow360/component/simulation/operating_condition/operating_condition.py @@ -497,6 +497,7 @@ def flow360_reynolds_number(self, length_unit: LengthType.Positive): """ Computes length_unit based Reynolds number. :math:`Re = \\rho_{\\infty} \\cdot U_{infty} \\cdot L_{grid}/\\mu_{\\infty}` where + - :math:`\\rho_{\\infty}` is the freestream fluid density. - :math:`U_{infty}` is the freestream velocity magnitude. - :math:`L_{grid}` is physical length represented by unit length in the given mesh/geometry file. From 7fedacc331e029e4f1d71c4c04f8311753cd86c0 Mon Sep 17 00:00:00 2001 From: wiktor-flex Date: Fri, 16 May 2025 22:04:59 +0200 Subject: [PATCH 19/19] added backslashes to make infty symboo --- .../simulation/operating_condition/operating_condition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flow360/component/simulation/operating_condition/operating_condition.py b/flow360/component/simulation/operating_condition/operating_condition.py index 368eb515b..319b88a25 100644 --- a/flow360/component/simulation/operating_condition/operating_condition.py +++ b/flow360/component/simulation/operating_condition/operating_condition.py @@ -496,10 +496,10 @@ def _update_input_cache(cls, value, info: pd.ValidationInfo): def flow360_reynolds_number(self, length_unit: LengthType.Positive): """ Computes length_unit based Reynolds number. - :math:`Re = \\rho_{\\infty} \\cdot U_{infty} \\cdot L_{grid}/\\mu_{\\infty}` where + :math:`Re = \\rho_{\\infty} \\cdot U_{\\infty} \\cdot L_{grid}/\\mu_{\\infty}` where - :math:`\\rho_{\\infty}` is the freestream fluid density. - - :math:`U_{infty}` is the freestream velocity magnitude. + - :math:`U_{\\infty}` is the freestream velocity magnitude. - :math:`L_{grid}` is physical length represented by unit length in the given mesh/geometry file. - :math:`\\mu_{\\infty}` is the dynamic eddy viscosity of the fluid of freestream.