diff --git a/amr-wind/physics/ActuatorSourceTagging.H b/amr-wind/physics/ActuatorSourceTagging.H new file mode 100644 index 0000000000..a4af7349a8 --- /dev/null +++ b/amr-wind/physics/ActuatorSourceTagging.H @@ -0,0 +1,46 @@ +#ifndef ACTUATORSOURCETAGGING_H +#define ACTUATORSOURCETAGGING_H + +#include "amr-wind/core/Physics.H" +#include "amr-wind/core/Field.H" +#include "amr-wind/core/IntField.H" + +namespace amr_wind { + +/** Tracer Tagging physics + * \ingroup physics + */ +class ActuatorSourceTagging : public Physics::Register +{ +public: + static std::string identifier() { return "ActuatorSourceTagging"; } + + explicit ActuatorSourceTagging(CFDSim& sim); + + ~ActuatorSourceTagging() override = default; + + void initialize_fields(int level, const amrex::Geometry& geom) override; + + void post_init_actions() override; + + void post_regrid_actions() override {} + + void pre_advance_work() override {} + + void post_advance_work() override; + +private: + const FieldRepo& m_repo; + Field* m_act_src{nullptr}; + IntField* m_iblank{nullptr}; + Field* m_tracer{nullptr}; + amrex::Real m_src_threshold{0.1}; + bool m_tag_hole{false}; + bool m_tag_fringe{true}; + bool m_has_act_src{false}; + bool m_has_iblank{false}; +}; + +} // namespace amr_wind + +#endif /* ACTUATORSOURCETAGGING_H */ diff --git a/amr-wind/physics/ActuatorSourceTagging.cpp b/amr-wind/physics/ActuatorSourceTagging.cpp new file mode 100644 index 0000000000..c8fa96719e --- /dev/null +++ b/amr-wind/physics/ActuatorSourceTagging.cpp @@ -0,0 +1,84 @@ +#include "amr-wind/CFDSim.H" +#include "amr-wind/physics/ActuatorSourceTagging.H" +#include "AMReX_ParmParse.H" + +namespace amr_wind { + +ActuatorSourceTagging::ActuatorSourceTagging(CFDSim& sim) : m_repo(sim.repo()) +{ + auto& pseqn = sim.pde_manager().register_transport_pde("PassiveScalar"); + m_tracer = &(pseqn.fields().field); + + amrex::ParmParse pp("ActuatorSourceTagging"); + pp.query("actuator_source_threshold", m_src_threshold); +} + +void ActuatorSourceTagging::initialize_fields( + int level, const amrex::Geometry& /*geom*/) +{ + (*m_tracer)(level).setVal(0.0); +} + +void ActuatorSourceTagging::post_init_actions() +{ + m_has_act_src = m_repo.field_exists("actuator_src_term"); + m_has_iblank = m_repo.field_exists("iblank_cell"); + + if (m_has_act_src) { + m_act_src = &(m_repo.get_field("actuator_src_term")); + } + + if (m_has_iblank) { + m_iblank = &(m_repo.get_int_field("iblank_cell")); + } +} + +void ActuatorSourceTagging::post_advance_work() +{ + if (!m_has_act_src && !m_has_iblank) { + amrex::Print() + << "Warning ActuatorSourceTagging activated but neither actuators " + "or overset are being used" + << std::endl; + return; + } + + const amrex::Real src_threshold = m_src_threshold; + for (int lev = 0; lev <= m_repo.mesh().finestLevel(); ++lev) { + + const auto& tracer_arrs = (*m_tracer)(lev).arrays(); + if (m_has_act_src) { + const auto& src_arrs = (*m_act_src)(lev).const_arrays(); + amrex::ParallelFor( + (*m_tracer)(lev), m_tracer->num_grow(), + [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k) noexcept { + const auto src = src_arrs[nbx]; + const amrex::Real srcmag = std::sqrt( + src(i, j, k, 0) * src(i, j, k, 0) + + src(i, j, k, 1) * src(i, j, k, 1) + + src(i, j, k, 2) * src(i, j, k, 2)); + + if (srcmag > src_threshold) { + tracer_arrs[nbx](i, j, k) = 1.0; + } + }); + } + + if (m_has_iblank) { + const auto& iblank_arrs = (*m_iblank)(lev).const_arrays(); + const bool tag_fringe = m_tag_fringe; + const bool tag_hole = m_tag_hole; + amrex::ParallelFor( + (*m_tracer)(lev), m_tracer->num_grow(), + [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k) noexcept { + const auto ib = iblank_arrs[nbx](i, j, k); + if ((tag_fringe && (ib == -1)) || (tag_hole && (ib == 0))) { + tracer_arrs[nbx](i, j, k) = 1.0; + } + }); + } + } + amrex::Gpu::synchronize(); +} + +} // namespace amr_wind diff --git a/amr-wind/physics/CMakeLists.txt b/amr-wind/physics/CMakeLists.txt index 218224c19f..f57edb26d1 100644 --- a/amr-wind/physics/CMakeLists.txt +++ b/amr-wind/physics/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources(${amr_wind_lib_name} ScalarAdvection.cpp VortexDipole.cpp BurggrafFlow.cpp + ActuatorSourceTagging.cpp ) add_subdirectory(multiphase) diff --git a/docs/sphinx/user/inputs_Actuator.rst b/docs/sphinx/user/inputs_Actuator.rst index bc93f571a3..bee227efac 100644 --- a/docs/sphinx/user/inputs_Actuator.rst +++ b/docs/sphinx/user/inputs_Actuator.rst @@ -1,15 +1,14 @@ - .. _inputs_actuator: Section: Actuator ~~~~~~~~~~~~~~~~~~ -This section controls the actuator type models. This includes the actuator -disk and line models. The prefix is the label set in +This section controls the actuator type models. This includes the actuator +disk and line models. The prefix is the label set in ``incflo.physics``. For example ``incflo.physics = FreeStream Actuator`` -Actuator models are meant to simulate aerodynamic objects by using body forces -in the momentum equation. +Actuator models are meant to simulate aerodynamic objects by using body forces +in the momentum equation. There are capabilities to simulate fixed wings as actuator lines and wind turbines as actuator disks and actuator line models. @@ -17,16 +16,16 @@ turbines as actuator disks and actuator line models. .. input_param:: Actuator.labels **type:** String, mandatory - + This string is used as an identifier for the current actuator. .. input_param:: Actuator.type **type:** String, mandatory - + This string identifies the type of actuator to use. The ones currently - supported are: ``TurbineFastLine``, ``TurbineFastDisk``, and + supported are: ``TurbineFastLine``, ``TurbineFastDisk``, and ``FixedWingLine``. It is recommended to group common parameters across actuators using the ``Actuator.[type].[param]``. For example:: @@ -48,43 +47,43 @@ FixedWingLine Example for ``FixedWingLine``:: - incflo.physics = FreeStream Actuator - Actuator.labels = F1 - Actuator.type = FixedWingLine - Actuator.FixedWingLine.num_points = 21 - Actuator.FixedWingLine.epsilon = 3.0 3.0 3.0 - Actuator.FixedWingLine.epsilon_chord = 0.25 0.25 0.25 + incflo.physics = FreeStream Actuator + Actuator.labels = F1 + Actuator.type = FixedWingLine + Actuator.FixedWingLine.num_points = 21 + Actuator.FixedWingLine.epsilon = 3.0 3.0 3.0 + Actuator.FixedWingLine.epsilon_chord = 0.25 0.25 0.25 Actuator.FixedWingLine.fllc = 0 - Actuator.FixedWingLine.pitch = 4.0 - Actuator.FixedWingLine.span_locs = 0.0 1.0 - Actuator.FixedWingLine.chord = 2.0 2.0 - Actuator.FixedWingLine.airfoil_table = DU21_A17.txt - Actuator.FixedWingLine.airfoil_type = openfast - Actuator.F1.start = 0.0 -4.0 0.0 - Actuator.F1.end = 0.0 4.0 0.0 - Actuator.F1.output_frequency = 10 - ICNS.source_terms = ActuatorForcing + Actuator.FixedWingLine.pitch = 4.0 + Actuator.FixedWingLine.span_locs = 0.0 1.0 + Actuator.FixedWingLine.chord = 2.0 2.0 + Actuator.FixedWingLine.airfoil_table = DU21_A17.txt + Actuator.FixedWingLine.airfoil_type = openfast + Actuator.F1.start = 0.0 -4.0 0.0 + Actuator.F1.end = 0.0 4.0 0.0 + Actuator.F1.output_frequency = 10 + ICNS.source_terms = ActuatorForcing .. input_param:: Actuator.FixedWingLine.num_points **type:** int, mandatory - - This is the number of actuator points along the wing to be used in the + + This is the number of actuator points along the wing to be used in the simulation. .. input_param:: Actuator.FixedWingLine.epsilon **type:** List of 3 real numbers, mandatory - + This is the value of epsilon in the chord, thicness and spanwise directions. .. input_param:: Actuator.FixedWingLine.epsilon_chord **type:** List of 3 real numbers, optional - - This is the value of epsilon/chord. This value will be used to compute - epsilon as a function of the chord at every actuator point. A value of - epsilon / chord ~ 0.25 is recommended for an optimal representation of the + + This is the value of epsilon/chord. This value will be used to compute + epsilon as a function of the chord at every actuator point. A value of + epsilon / chord ~ 0.25 is recommended for an optimal representation of the blade aerodynamics. When this variable is specified, the code will choose the maximum value between ``epsilon_chord * chord`` and ``epsilon`` for every actuator point. @@ -146,8 +145,8 @@ Example for ``FixedWingLine``:: .. input_param:: Actuator.FixedWingLine.pitch **type:** Real number, mandatory - - This is the pitch angle of the blade in degrees. All coordinates will be + + This is the pitch angle of the blade in degrees. All coordinates will be pitched by this angle. In the case of a fixed wing, this would be the angle of attack of the wing with respect to the inflow velocity. This argument is mandatory unless a pitch timetable is specified. @@ -162,21 +161,21 @@ Example for ``FixedWingLine``:: .. input_param:: Actuator.FixedWingLine.chord **type:** List of real numbers, mandatory - - These are the chord values at every span location. The length of this array + + These are the chord values at every span location. The length of this array needs to be the same length as ``span_locs``. .. input_param:: Actuator.FixedWingLine.airfoil_table **type:** String, mandatory - + This is the name of the file that contains the lookup table for lift and drag coefficients. .. input_param:: Actuator.FixedWingLine.airfoil_type **type:** String, mandatory - + This is the type of airfoil table lookup. The currently supported options are ``openfast`` and ``text``. @@ -195,15 +194,15 @@ Example for ``FixedWingLine``:: .. input_param:: Actuator.F1.output_frequency **type:** int, optional - + This is how often to write actuator output. The default is ``10``. .. input_param:: Actuator.FixedWingLine.motion_type **type:** String, optional - The FixedWingLine actuator allows for motion, - though other aspects of the actuator remain fixed (such as the orientation and + The FixedWingLine actuator allows for motion, + though other aspects of the actuator remain fixed (such as the orientation and the dimensions). The currently supported options are ``none`` (default), ``linear``, and ``sine``. Linear motion moves the actuator at a constant velocity in a straight line whereas sine motion oscillates the actuator according to a temporal sine signal. @@ -232,7 +231,7 @@ Example for ``FixedWingLine``:: **type:** String, optional - File name of pitch timetable. This file must specify pitch angles + File name of pitch timetable. This file must specify pitch angles at different times below a one-line header. When this argument is present, the ``pitch`` argument is no longer mandatory, and it will not be used. @@ -242,7 +241,7 @@ Example for ``FixedWingLine``:: When this option is turned on, the actuator Gaussian is disabled in the spanwise Gaussian, making the force distribution uniform in that direction. This option enables quasi-2D simulations - with a fixed wing. The code will print warning statements if the detected spanwise direction is + with a fixed wing. The code will print warning statements if the detected spanwise direction is not periodic. .. input_param:: Actuator.FixedWingLine.normalize_spanwise @@ -266,8 +265,8 @@ Example for ``FixedWingLine``:: **type:** List of 3 real numbers, optional, default = 1.0 1.0 1.0 - By default, the actuator force is computed and applied in every coordinate direction. - This input allows actuator force coordinate directions to be deactivated by specifying a 0.0 in + By default, the actuator force is computed and applied in every coordinate direction. + This input allows actuator force coordinate directions to be deactivated by specifying a 0.0 in for the x, y, or z component of this vector. @@ -300,25 +299,25 @@ Example for ``TurbineFastLine``:: .. input_param:: Actuator.TurbineFastLine.rotor_diameter **type:** Real number, required - + This is the rotor diameter of the turbine to be simulated. .. input_param:: Actuator.TurbineFastLine.hub_height **type:** Real number, required - + This is the hub height of the turbine. .. input_param:: Actuator.TurbineFastLine.num_points_blade **type:** int, required - + This the number of actuator points along the blades. .. input_param:: Actuator.TurbineFastLine.num_points_tower **type:** int, required - + This is the number of actuator points along the tower. .. input_param:: Actuator.TurbineFastLine.epsilon @@ -344,20 +343,20 @@ Example for ``TurbineFastLine``:: .. input_param:: Actuator.TurbineFastLine.openfast_start_time **type:** Real, required - + This is the time at which to start the openfast simulation. .. input_param:: Actuator.TurbineFastLine.openfast_stop_time **type:** Real, required - + This is the time at which to stop the openfast run. -.. input_param:: Actuator.TurbineFastLine.nacelle_drag_coeff +.. input_param:: Actuator.TurbineFastLine.nacelle_drag_coeff **type:** Real, optional - - This is the drag coefficient of the nacelle. If this and the area of the + + This is the drag coefficient of the nacelle. If this and the area of the nacelle are specified, a value of epsilon for the nacelle is computed that would provide an optimal momentum thickness of the wake. This is also used to correct the sampled velocity at the location of the @@ -366,30 +365,68 @@ Example for ``TurbineFastLine``:: .. input_param:: Actuator.TurbineFastLine.nacelle_area **type:** Real, optional, default=0 - + This is the frontal area of the nacelle which is used to compute the force. .. input_param:: Actuator.TurbineFastLine.output_frequency **type:** int, optional, default=10 - - This is how often to write actuator output. + + This is how often to write actuator output. .. input_param:: Actuator.TurbineFastLine.density **type:** Real, optional - - This is the density of the fluid specified in openfast. This is used to + + This is the density of the fluid specified in openfast. This is used to non-dimensionalize the forces from openfast. .. input_param:: Actuator.WTG01.openfast_input_file **type:** String, required - + This is the name of the openfast input file with all the turbine information. +ActuatorSourceTagging +""""""""""""""""""""" + +It is possible to seed a passive scalar in the flow field at locations +where the actuator source term value is above a certain +threshold. This is useful for wake visualization and for dynamic +adaptation of the mesh to the wake location. This is activated by +adding ``ActuatorSourceTagging`` to ``incflo.physics``. It has the +following input options: + +.. input_param:: ActuatorSourceTagging.actuator_source_threshold + + **type:** Real, optional, default=0.1 + + Threshold value for the actuator source term above which the passive scalar will be set to 1.0. + + +Additional input parameters are +``transport.passive_scalar_laminar_schmidt`` and +``transport.passive_scalar_turbulent_schmidt`` to set the diffusion of +the passive scalar. This can be combined with the ``FieldRefinement`` +criteria for mesh adaptation: + +.. code-block:: console + + tagging.labels = tracer + tagging.tracer.type = FieldRefinement + tagging.tracer.field_name = passive_scalar + tagging.tracer.field_error = 0.3 0.3 0.3 0.3 +where the ``field_error`` is the value above which the cells should be +tagged for refinement. Here is an example using the +uniform_ct_disk_dynamic_adaptation regression test: +.. image:: ./uniform_ct_disk_dynamic_adaptation.gif + :width: 300pt +.. warning:: + This is an experimental feature and there is no guidance yet on the + values that should be used for the passive scalar and tagging + criteria. diff --git a/docs/sphinx/user/uniform_ct_disk_dynamic_adaptation.gif b/docs/sphinx/user/uniform_ct_disk_dynamic_adaptation.gif new file mode 100644 index 0000000000..f932d3b871 Binary files /dev/null and b/docs/sphinx/user/uniform_ct_disk_dynamic_adaptation.gif differ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 919e0bcd3c..11fb5ae1c6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -199,6 +199,7 @@ add_test_re(act_flat_plate) add_test_re(boussinesq_bubble_mol) add_test_re(uniform_ct_disk) add_test_re(uniform_ct_disk_gaussian) +add_test_re(uniform_ct_disk_dynamic_adaptation) add_test_re(joukowsky_disk) add_test_re(channel_kwsst) add_test_re(channel_kwsst_sust) diff --git a/test/test_files/cylinder_refinement/cylinder_refinement.inp b/test/test_files/cylinder_refinement/cylinder_refinement.inp index eb30de9c6d..4186ac8fe3 100755 --- a/test/test_files/cylinder_refinement/cylinder_refinement.inp +++ b/test/test_files/cylinder_refinement/cylinder_refinement.inp @@ -35,8 +35,6 @@ Actuator.UniformCtDisk.sample_yaw = 270.0 # set velocity sampling to be in the n Actuator.UniformCtDisk.thrust_coeff = 0.0 0.7 1.2 Actuator.UniformCtDisk.wind_speed = 0.0 10.0 12.0 Actuator.UniformCtDisk.epsilon = 10.0 -Actuator.UniformCtDisk.density = 1.225 -Actuator.UniformCtDisk.diameters_to_sample = 1.0 Actuator.UniformCtDisk.num_points_r = 5 Actuator.UniformCtDisk.num_points_t = 20 diff --git a/test/test_files/uniform_ct_disk/uniform_ct_disk.inp b/test/test_files/uniform_ct_disk/uniform_ct_disk.inp index aa4b334d9f..55bd354272 100755 --- a/test/test_files/uniform_ct_disk/uniform_ct_disk.inp +++ b/test/test_files/uniform_ct_disk/uniform_ct_disk.inp @@ -34,7 +34,6 @@ Actuator.UniformCtDisk.sample_yaw = 270.0 # set velocity sampling to be in the n Actuator.UniformCtDisk.thrust_coeff = 0.0 0.7 1.2 Actuator.UniformCtDisk.wind_speed = 0.0 10.0 12.0 Actuator.UniformCtDisk.epsilon = 10.0 -Actuator.UniformCtDisk.density = 1.225 Actuator.UniformCtDisk.diameters_to_sample = 1.0 Actuator.UniformCtDisk.num_points_r = 5 Actuator.UniformCtDisk.num_points_t = 3 diff --git a/test/test_files/uniform_ct_disk_dynamic_adaptation/uniform_ct_disk_dynamic_adaptation.inp b/test/test_files/uniform_ct_disk_dynamic_adaptation/uniform_ct_disk_dynamic_adaptation.inp new file mode 100644 index 0000000000..8b8a683543 --- /dev/null +++ b/test/test_files/uniform_ct_disk_dynamic_adaptation/uniform_ct_disk_dynamic_adaptation.inp @@ -0,0 +1,84 @@ +time.stop_time = -100.0 # Max (simulated) time to evolve +time.max_step = 200 # Max number of time steps + +time.fixed_dt = -0.1 # Use this constant dt if > 0 +time.cfl = 0.5 # CFL factor + +io.outputs = actuator_src_term +io.derived_outputs = q_criterion q_criterion_nondim mag_vorticity +time.plot_interval = 10 # Steps between plot files +time.checkpoint_interval = -1 # Steps between checkpoint files +time.regrid_interval = 1 + +ConstValue.density.value = 1.0 +ConstValue.velocity.value = 6.0 -3.0 0.0 +ConstValue.passive_scalar.value = 0.0 + +incflo.use_godunov = 1 +incflo.godunov_type = "weno_z" +incflo.do_initial_proj = 1 +incflo.initial_iterations = 3 +transport.viscosity = 1.0e-5 +transport.laminar_prandtl = 0.7 +transport.turbulent_prandtl = 0.3333 +transport.passive_scalar_laminar_schmidt = 1.0e-5 +transport.passive_scalar_turbulent_schmidt = 1.0e-3 +turbulence.model = Smagorinsky +Smagorinsky_coeffs.Cs = 0.16 + +incflo.physics = FreeStream ActuatorSourceTagging Actuator +Actuator.labels = WTG01 +Actuator.type = UniformCtDisk + +Actuator.UniformCtDisk.rotor_diameter = 126.0 +Actuator.UniformCtDisk.base_position = 0.0 0.0 0.0 +Actuator.UniformCtDisk.hub_height = 0.0 +Actuator.UniformCtDisk.yaw = 315.0 # degrees (yaw is relative to north which defaults to {0,1,0}) +Actuator.UniformCtDisk.sample_yaw = 270.0 # set velocity sampling to be in the normal flow direction +Actuator.UniformCtDisk.thrust_coeff = 0.0 0.7 1.2 +Actuator.UniformCtDisk.wind_speed = 0.0 10.0 12.0 +Actuator.UniformCtDisk.epsilon = 10.0 +Actuator.UniformCtDisk.diameters_to_sample = 1.0 +Actuator.UniformCtDisk.num_points_r = 5 +Actuator.UniformCtDisk.num_points_t = 3 + +ICNS.source_terms = ActuatorForcing + +amr.n_cell = 64 64 64 # Grid cells at coarsest AMRlevel +amr.max_level = 1 # Max AMR level in hierarchy +geometry.prob_lo = -315.0 -315.0 -315.0 +geometry.prob_hi = 315.0 315.0 315.0 + +geometry.is_periodic = 0 0 0 # Periodicity x y z (0/1) + +#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨# +# Mesh refinement # +#.......................................# +tagging.labels = tracer +tagging.tracer.type = FieldRefinement +tagging.tracer.field_name = passive_scalar +tagging.tracer.field_error = 0.3 0.3 0.3 0.3 + +# Boundary conditions +xlo.type = "mass_inflow" +xlo.density = 1.0 +xlo.velocity = 6.0 -3.0 0.0 +xlo.passive_scalar = 0.0 +xhi.type = "pressure_outflow" + +yhi.type = "mass_inflow" +yhi.density = 1.0 +yhi.velocity = 6.0 -3.0 0.0 +yhi.passive_scalar = 0.0 +ylo.type = "pressure_outflow" + +zlo.type = "slip_wall" +zhi.type = "slip_wall" + +incflo.verbose = 0 # incflo_level +nodal_proj.verbose = 0 + +nodal_proj.mg_rtol = 1.0e-6 +nodal_proj.mg_atol = 1.0e-12 +mac_proj.mg_rtol = 1.0e-6 +mac_proj.mg_atol = 1.0e-12 diff --git a/test/test_files/uniform_ct_disk_gaussian/uniform_ct_disk_gaussian.inp b/test/test_files/uniform_ct_disk_gaussian/uniform_ct_disk_gaussian.inp index 21aa670fbd..1895ceaf60 100755 --- a/test/test_files/uniform_ct_disk_gaussian/uniform_ct_disk_gaussian.inp +++ b/test/test_files/uniform_ct_disk_gaussian/uniform_ct_disk_gaussian.inp @@ -35,7 +35,6 @@ Actuator.UniformCtDisk.sample_yaw = 270.0 # set velocity sampling to be in the n Actuator.UniformCtDisk.thrust_coeff = 0.0 0.7 1.2 Actuator.UniformCtDisk.wind_speed = 0.0 10.0 12.0 Actuator.UniformCtDisk.epsilon = 10.0 -Actuator.UniformCtDisk.density = 1.225 Actuator.UniformCtDisk.diameters_to_sample = 1.0 Actuator.UniformCtDisk.num_points_r = 5 Actuator.UniformCtDisk.num_points_t = 20