@@ -147,6 +147,37 @@ void init_vof_diffuse(amr_wind::Field& vof_fld, amrex::Real water_level)
147
147
amrex::Gpu::streamSynchronize ();
148
148
}
149
149
150
+ void init_vof_outliers (
151
+ amr_wind::Field& vof_fld, amrex::Real water_level, bool distort_above)
152
+ {
153
+ const auto & mesh = vof_fld.repo ().mesh ();
154
+ const int nlevels = vof_fld.repo ().num_active_levels ();
155
+
156
+ // Since VOF is cell centered
157
+ amrex::Real offset = 0.5 ;
158
+
159
+ for (int lev = 0 ; lev < nlevels; ++lev) {
160
+ const auto & dx = mesh.Geom (lev).CellSizeArray ();
161
+ const auto & problo = mesh.Geom (lev).ProbLoArray ();
162
+ const auto & farrs = vof_fld (lev).arrays ();
163
+
164
+ amrex::ParallelFor (
165
+ vof_fld (lev), vof_fld.num_grow (),
166
+ [=] AMREX_GPU_DEVICE (int nbx, int i, int j, int k) noexcept {
167
+ const amrex::Real z = problo[2 ] + (k + offset) * dx[2 ];
168
+ if (std::abs (water_level - z) < 0.5 * dx[2 ]) {
169
+ farrs[nbx](i, j, k) =
170
+ (water_level - (z - 0.5 * dx[2 ])) / dx[2 ];
171
+ } else if (z > water_level) {
172
+ farrs[nbx](i, j, k) = distort_above ? 0.1 : 0.0 ;
173
+ } else {
174
+ farrs[nbx](i, j, k) = !distort_above ? 0.9 : 1.0 ;
175
+ }
176
+ });
177
+ }
178
+ amrex::Gpu::streamSynchronize ();
179
+ }
180
+
150
181
// ! Custom mesh class to be able to refine like a simulation would
151
182
// - combination of AmrTestMesh and incflo classes
152
183
// - with ability to initialize the refiner and regrid
@@ -380,6 +411,17 @@ class FreeSurfaceTest : public MeshTest
380
411
pp.addarr (" plane_end" , m_pt_coord);
381
412
}
382
413
void setup_grid_0d (int ninst) { setup_grid_0d (ninst, " freesurface" ); }
414
+ void setup_grid_0d (int ninst, amrex::Real xy_sample)
415
+ {
416
+ amrex::ParmParse pp (" freesurface" );
417
+ pp.add (" output_interval" , 1 );
418
+ pp.add (" num_instances" , ninst);
419
+ pp.addarr (" plane_num_points" , amrex::Vector<int >{1 , 1 });
420
+ const amrex::Vector<amrex::Real> pt_coord{
421
+ xy_sample, xy_sample, m_pt_coord[2 ]};
422
+ pp.addarr (" plane_start" , pt_coord);
423
+ pp.addarr (" plane_end" , pt_coord);
424
+ }
383
425
void setup_grid_2d (int ninst)
384
426
{
385
427
amrex::ParmParse pp (" freesurface" );
@@ -667,4 +709,127 @@ TEST_F(FreeSurfaceTest, point_diffuse)
667
709
ASSERT_EQ (nout, 1 );
668
710
}
669
711
712
+ TEST_F (FreeSurfaceTest, point_outliers)
713
+ {
714
+ initialize_mesh ();
715
+ auto & repo = sim ().repo ();
716
+ auto & vof = repo.declare_field (" vof" , 1 , 2 );
717
+ setup_grid_0d (1 );
718
+ {
719
+ amrex::ParmParse pp (" freesurface" );
720
+ pp.add (" linear_interp_extent_from_xhi" , 66.1 );
721
+ }
722
+
723
+ amrex::Real water_lev = 61.5 ;
724
+ // Sets up field with multiphase cells above interface
725
+ init_vof_outliers (vof, water_lev, true );
726
+ auto & m_sim = sim ();
727
+ FreeSurfaceImpl tool (m_sim);
728
+ tool.initialize (" freesurface" );
729
+ tool.update_sampling_locations ();
730
+
731
+ // Linear interpolation will get different value
732
+ amrex::Real local_vof = (water_lev - 60 .) / 2.0 ;
733
+ amrex::Real water_lev_linear =
734
+ 61 . + (0.5 - local_vof) * (2 . / (0.1 - local_vof));
735
+
736
+ // Check output value
737
+ int nout = tool.check_output (" ~" , water_lev_linear);
738
+ ASSERT_EQ (nout, 1 );
739
+ // Check sampling locations
740
+ int nsloc = tool.check_sloc (" ~" );
741
+ ASSERT_EQ (nsloc, 1 );
742
+
743
+ // Now distort VOF field below interface
744
+ init_vof_outliers (vof, water_lev, false );
745
+ tool.update_sampling_locations ();
746
+ water_lev_linear = 61 . + (0.5 - local_vof) * (2 . / (0 . - local_vof));
747
+ nout = tool.check_output (" ~" , water_lev_linear);
748
+ ASSERT_EQ (nout, 1 );
749
+ nsloc = tool.check_sloc (" ~" );
750
+ ASSERT_EQ (nsloc, 1 );
751
+
752
+ // Repeat with target cell having 0 < vof < 0.5
753
+ water_lev = 60.5 ;
754
+ init_vof_outliers (vof, water_lev, true );
755
+ tool.update_sampling_locations ();
756
+ local_vof = (water_lev - 60 .) / 2.0 ;
757
+ water_lev_linear = 61 . - (0.5 - local_vof) * (2 . / (1.0 - local_vof));
758
+ nout = tool.check_output (" ~" , water_lev_linear);
759
+ ASSERT_EQ (nout, 1 );
760
+ init_vof_outliers (vof, water_lev, false );
761
+ tool.update_sampling_locations ();
762
+ water_lev_linear = 61 . - (0.5 - local_vof) * (2 . / (0.9 - local_vof));
763
+ nout = tool.check_output (" ~" , water_lev_linear);
764
+ ASSERT_EQ (nout, 1 );
765
+ nsloc = tool.check_sloc (" ~" );
766
+ ASSERT_EQ (nsloc, 1 );
767
+ }
768
+
769
+ TEST_F (FreeSurfaceTest, point_outliers_off)
770
+ {
771
+ initialize_mesh ();
772
+ auto & repo = sim ().repo ();
773
+ auto & vof = repo.declare_field (" vof" , 1 , 2 );
774
+ setup_grid_0d (1 );
775
+ {
776
+ amrex::ParmParse pp (" freesurface" );
777
+ pp.add (" linear_interp_extent_from_xhi" , 64 );
778
+ }
779
+
780
+ amrex::Real water_lev = 61.5 ;
781
+ // Sets up field with multiphase cells above interface
782
+ init_vof_outliers (vof, water_lev, true );
783
+ auto & m_sim = sim ();
784
+ FreeSurfaceImpl tool (m_sim);
785
+ tool.initialize (" freesurface" );
786
+ tool.update_sampling_locations ();
787
+
788
+ // Because linear interpolation is off and there are multiphase cells all
789
+ // the way above the interface, it will get a bad value, middle of top cell
790
+ const amrex::Real water_lev_geom = 123 .;
791
+
792
+ // Check output value
793
+ int nout = tool.check_output (" ~" , water_lev_geom);
794
+ ASSERT_EQ (nout, 1 );
795
+ }
796
+
797
+ TEST_F (FreeSurfaceTest, point_diffuse_in_single_phase)
798
+ {
799
+ initialize_mesh ();
800
+ sim ().activate_overset ();
801
+ auto & repo = sim ().repo ();
802
+ auto & vof = repo.declare_field (" vof" , 1 , 2 );
803
+ auto & iblank = repo.get_int_field (" iblank_cell" );
804
+ iblank.setVal (-1 );
805
+ // Set up sampler to be on lateral edge of cell
806
+ setup_grid_0d (1 , 64 . - 0.1 );
807
+
808
+ // Set up water level to be just below bottom edge of cell
809
+ const amrex::Real water_lev_diffuse = 60 . - 0.1 ;
810
+ const amrex::Real vof_slope = 0.1 ;
811
+ // Set up vof with nonzero slope but 0 in current cell
812
+ init_vof_slope (vof, water_lev_diffuse, vof_slope, 124 .);
813
+ auto & m_sim = sim ();
814
+ FreeSurfaceImpl tool (m_sim);
815
+ tool.initialize (" freesurface" );
816
+ tool.update_sampling_locations ();
817
+
818
+ // Check output value
819
+ const amrex::Real vof_cell = 0 .;
820
+ const amrex::Real vof_mz = (water_lev_diffuse - 58 .) / 2 .;
821
+ const amrex::Real vof_pxy = (water_lev_diffuse + 4 . * vof_slope - 60 .) / 2 .;
822
+ const amrex::Real vof_c =
823
+ vof_cell + 2 . * (vof_pxy - vof_cell) / 4.0 * (2.0 - 0.1 );
824
+ const amrex::Real slope_z = (vof_cell - vof_mz) / 2 .;
825
+ const amrex::Real ht =
826
+ 61 . + (0.5 - vof_c) / (slope_z + amr_wind::constants::EPS);
827
+ const amrex::Real ht_est =
828
+ water_lev_diffuse + 2.0 * vof_slope * (2.0 - 0.1 );
829
+ int nout = tool.check_output (" ~" , ht);
830
+ ASSERT_EQ (nout, 1 );
831
+ // The linear interpolation answer should be close to the naive calc
832
+ EXPECT_NEAR (ht, ht_est, 5e-2 );
833
+ }
834
+
670
835
} // namespace amr_wind_tests
0 commit comments