@@ -878,6 +878,132 @@ def test_heat_charge_bcs_validation(boundary_conditions):
878
878
td .VoltageBC (source = td .DCVoltageSource (voltage = np .array ([td .inf , 0 , 1 ])))
879
879
880
880
881
+ def test_vertical_natural_convection ():
882
+ solid_box_l = td .Box (center = (0 , 0 , 0 ), size = (2 , 2 , 2 ))
883
+ solid_box_r = td .Box (center = (1 , 1 , 1 ), size = (2 , 2 , 2 ))
884
+ fluid_box_r = td .Box (center = (1 , 1 , 1 ), size = (2 , 2 , 2 ))
885
+
886
+ solid_medium = td .MultiPhysicsMedium (
887
+ heat = td .SolidMedium (conductivity = 1 , capacity = 1 ), name = "solid"
888
+ )
889
+ air = td .MultiPhysicsMedium (
890
+ heat = td .FluidMedium .from_si_units (
891
+ thermal_conductivity = 0.026 ,
892
+ viscosity = 1.8e-5 ,
893
+ specific_heat = 1005 ,
894
+ density = 1.2 ,
895
+ expansivity = 1 / 300.0 ,
896
+ ),
897
+ name = "air" ,
898
+ )
899
+ solid_structure_l = td .Structure (
900
+ geometry = solid_box_l ,
901
+ medium = solid_medium ,
902
+ name = "solid_l" ,
903
+ )
904
+ solid_structure_r = td .Structure (
905
+ geometry = solid_box_r ,
906
+ medium = solid_medium ,
907
+ name = "solid_r" ,
908
+ )
909
+ fluid_structure_r = td .Structure (
910
+ geometry = fluid_box_r ,
911
+ medium = air ,
912
+ name = "fluid_r" ,
913
+ )
914
+
915
+ coeff_model = td .VerticalNaturalConvectionCoeffModel (plate_length = 1 )
916
+ full_coeff_model = td .VerticalNaturalConvectionCoeffModel (medium = air .heat , plate_length = 1 )
917
+ sim = td .HeatChargeSimulation (
918
+ size = (2 , 2 , 2 ),
919
+ center = (0 , 0 , 0 ),
920
+ medium = td .MultiPhysicsMedium (heat = td .FluidMedium ()),
921
+ structures = [solid_structure_l , fluid_structure_r ],
922
+ boundary_spec = [
923
+ td .HeatBoundarySpec (
924
+ placement = td .MediumMediumInterface (mediums = ["air" , "solid" ]),
925
+ condition = td .ConvectionBC (ambient_temperature = 300 , transfer_coeff = coeff_model ),
926
+ )
927
+ ],
928
+ grid_spec = td .UniformUnstructuredGrid (dl = 0.1 ),
929
+ monitors = [
930
+ td .TemperatureMonitor (
931
+ center = (0 , 0 , 0 ),
932
+ size = (td .inf , td .inf , td .inf ),
933
+ name = "test_monitor" ,
934
+ unstructured = True ,
935
+ )
936
+ ],
937
+ )
938
+
939
+ # Test that the model can be placed on an interface defined by structures
940
+ sim .updated_copy (
941
+ boundary_spec = [
942
+ td .HeatBoundarySpec (
943
+ placement = td .StructureStructureInterface (structures = ["solid_l" , "fluid_r" ]),
944
+ condition = td .ConvectionBC (ambient_temperature = 300 , transfer_coeff = coeff_model ),
945
+ )
946
+ ],
947
+ )
948
+
949
+ # Verify that placing the model on an interface between two solid media
950
+ # correctly raises a validation error.
951
+ with pytest .raises (pd .ValidationError ):
952
+ sim .updated_copy (
953
+ structures = [solid_structure_l , solid_structure_r ],
954
+ boundary_spec = [
955
+ td .HeatBoundarySpec (
956
+ placement = td .StructureStructureInterface (structures = ["solid_l" , "solid_r" ]),
957
+ condition = td .ConvectionBC (ambient_temperature = 300 , transfer_coeff = coeff_model ),
958
+ )
959
+ ],
960
+ )
961
+
962
+ # Verify that using a fluid medium with incomplete physical properties
963
+ # for the natural convection calculation raises a validation error.
964
+ incomplete_air = td .MultiPhysicsMedium (
965
+ heat = td .FluidMedium (expansivity = 1 / 300.0 ), name = "incomplete_air"
966
+ )
967
+ with pytest .raises (pd .ValidationError ):
968
+ new_fluid_structure_r = fluid_structure_r .updated_copy (medium = incomplete_air )
969
+ sim .updated_copy (
970
+ structures = [solid_structure_l , new_fluid_structure_r ],
971
+ boundary_spec = [
972
+ td .HeatBoundarySpec (
973
+ placement = td .MediumMediumInterface (mediums = ["incomplete_air" , "solid" ]),
974
+ condition = td .ConvectionBC (ambient_temperature = 300 , transfer_coeff = coeff_model ),
975
+ )
976
+ ],
977
+ )
978
+
979
+ # Test the case where the convection model has its own fluid medium explicitly defined.
980
+ # The simulation should use the properties from the model's medium and ignore the
981
+ # fluid present at the interface.
982
+ sim .updated_copy (
983
+ boundary_spec = [
984
+ td .HeatBoundarySpec (
985
+ placement = td .StructureStructureInterface (structures = ["solid_l" , "fluid_r" ]),
986
+ condition = td .ConvectionBC (ambient_temperature = 300 , transfer_coeff = full_coeff_model ),
987
+ )
988
+ ],
989
+ )
990
+
991
+ # Verify that a validation error is raised if the medium supplied directly to the
992
+ # coefficient model has incomplete properties for the natural convection calculation.
993
+ incomplete_coeff_model = coeff_model .updated_copy (medium = incomplete_air .heat )
994
+ with pytest .raises (pd .ValidationError ):
995
+ sim .updated_copy (
996
+ boundary_spec = [
997
+ td .HeatBoundarySpec (
998
+ placement = td .MediumMediumInterface (mediums = ["air" , "solid" ]),
999
+ condition = td .ConvectionBC (
1000
+ ambient_temperature = 300 , transfer_coeff = incomplete_coeff_model
1001
+ ),
1002
+ ),
1003
+ ]
1004
+ )
1005
+
1006
+
881
1007
def test_heat_charge_monitors_validation (monitors ):
882
1008
"""Checks for no name and negative size in monitors."""
883
1009
temp_mnt = monitors [0 ]
0 commit comments