diff --git a/CMakeLists.txt b/CMakeLists.txt index cb145bee2a..d6fb016ebd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required (VERSION 3.20 FATAL_ERROR) project(AMR-Wind CXX C) set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") include(CMakePackageConfigHelpers) include(GNUInstallDirs) include(amr-wind-utils) @@ -129,6 +129,10 @@ endif() include(set_compile_flags) +if(ERF_AMR_WIND_MULTIBLOCK) + target_compile_definitions(${amr_wind_lib_name} PUBLIC ERF_AMR_WIND_MULTIBLOCK) +endif() + if (AMR_WIND_ENABLE_W2A) # Turn on the use of the library via bool, it has already been included above target_compile_definitions(${amr_wind_lib_name} PUBLIC AMR_WIND_USE_W2A) @@ -185,7 +189,7 @@ if(AMR_WIND_ENABLE_ASCENT) target_compile_definitions(${amr_wind_lib_name} PRIVATE AMR_WIND_USE_ASCENT) endif() -# Link with HELICS module +# Link with HELICS module if(AMR_WIND_ENABLE_HELICS) set(CMAKE_PREFIX_PATH ${HELICS_DIR} ${CMAKE_PREFIX_PATH}) find_package(HELICS 3 REQUIRED) diff --git a/amr-wind/CFDSim.H b/amr-wind/CFDSim.H index 12a7299e95..7207ec7b1d 100644 --- a/amr-wind/CFDSim.H +++ b/amr-wind/CFDSim.H @@ -9,6 +9,11 @@ #include "amr-wind/core/MeshMap.H" #include "amr-wind/helics.H" +#ifdef ERF_AMR_WIND_MULTIBLOCK +#include "amr-wind/wind_energy/ABLReadERFFcn.H" +class MultiBlockContainer; +#endif + /** AMR-Wind * * All C++ code in AMR-Wind is organized within the amr_wind namespace. @@ -58,6 +63,14 @@ public: SimTime& time() { return m_time; } const SimTime& time() const { return m_time; } +#ifdef ERF_AMR_WIND_MULTIBLOCK + void set_mbc(MultiBlockContainer* mbc) { m_mbc = mbc; } + MultiBlockContainer** mbc() { return &m_mbc; } + + void set_read_erf(ReadERFFunction fcn) { m_read_erf = fcn; } + ReadERFFunction* get_read_erf() { return &m_read_erf; } +#endif + //! Return the field repository FieldRepo& repo() { return m_repo; } FieldRepo& repo() const { return m_repo; } @@ -145,6 +158,11 @@ private: std::unique_ptr m_helics; bool m_mesh_mapping{false}; + +#ifdef ERF_AMR_WIND_MULTIBLOCK + MultiBlockContainer* m_mbc = nullptr; + ReadERFFunction m_read_erf{nullptr}; +#endif }; } // namespace amr_wind diff --git a/amr-wind/CMakeLists.txt b/amr-wind/CMakeLists.txt index 1757ceab0e..9336e53176 100644 --- a/amr-wind/CMakeLists.txt +++ b/amr-wind/CMakeLists.txt @@ -38,7 +38,7 @@ include(AMReXBuildInfo) generate_buildinfo(${amr_wind_lib_name} ${CMAKE_SOURCE_DIR}) # Generate AMR-Wind version header -configure_file("${CMAKE_SOURCE_DIR}/cmake/AMRWindVersion.H.in" +configure_file("${PROJECT_SOURCE_DIR}/cmake/AMRWindVersion.H.in" "${CMAKE_CURRENT_BINARY_DIR}/AMRWindVersion.H" @ONLY) target_link_libraries_system(${amr_wind_lib_name} PUBLIC AMReX::amrex AMReX-Hydro::amrex_hydro_api) diff --git a/amr-wind/equation_systems/icns/source_terms/ABLMesoForcingMom.cpp b/amr-wind/equation_systems/icns/source_terms/ABLMesoForcingMom.cpp index 2b0924ba84..0f058634d2 100644 --- a/amr-wind/equation_systems/icns/source_terms/ABLMesoForcingMom.cpp +++ b/amr-wind/equation_systems/icns/source_terms/ABLMesoForcingMom.cpp @@ -101,7 +101,7 @@ void ABLMesoForcingMom::mean_velocity_heights( currtime = m_time.current_time(); // First the index in time - m_idx_time = utils::closest_index(ncfile->meso_times(), currtime); + m_idx_time = utils::closest_index_ubound(ncfile->meso_times(), currtime); amrex::Array coeff_interp{0.0, 0.0}; @@ -154,7 +154,7 @@ void ABLMesoForcingMom::mean_velocity_heights( const auto& dt = m_time.delta_t(); // First the index in time - m_idx_time = utils::closest_index(ncfile->meso_times(), currtime); + m_idx_time = utils::closest_index_ubound(ncfile->meso_times(), currtime); amrex::Array coeff_interp{0.0, 0.0}; diff --git a/amr-wind/equation_systems/temperature/source_terms/ABLMesoForcingTemp.cpp b/amr-wind/equation_systems/temperature/source_terms/ABLMesoForcingTemp.cpp index 2f9543fc54..6ee65ba77e 100644 --- a/amr-wind/equation_systems/temperature/source_terms/ABLMesoForcingTemp.cpp +++ b/amr-wind/equation_systems/temperature/source_terms/ABLMesoForcingTemp.cpp @@ -92,7 +92,7 @@ amrex::Real ABLMesoForcingTemp::mean_temperature_heights( currtime = m_time.current_time(); // First the index in time - m_idx_time = utils::closest_index(ncfile->meso_times(), currtime); + m_idx_time = utils::closest_index_ubound(ncfile->meso_times(), currtime); amrex::Array coeff_interp{0.0, 0.0}; @@ -145,7 +145,7 @@ amrex::Real ABLMesoForcingTemp::mean_temperature_heights( const auto& dt = m_time.delta_t(); // First the index in time - m_idx_time = utils::closest_index(ncfile->meso_times(), currtime); + m_idx_time = utils::closest_index_ubound(ncfile->meso_times(), currtime); amrex::Array coeff_interp{0.0, 0.0}; diff --git a/amr-wind/incflo.H b/amr-wind/incflo.H index 406af2077e..5a8f1b76ba 100644 --- a/amr-wind/incflo.H +++ b/amr-wind/incflo.H @@ -13,6 +13,10 @@ #include "amr-wind/core/FieldRepo.H" #include "amr-wind/overset/OversetOps.H" +#ifdef ERF_AMR_WIND_MULTIBLOCK +#include "amr-wind/wind_energy/ABLReadERFFcn.H" +class MultiBlockContainer; +#endif namespace amr_wind { namespace pde { class PDEBase; @@ -58,6 +62,11 @@ public: // Evolve solution to final time through repeated calls to Advance() void Evolve(); +#ifdef ERF_AMR_WIND_MULTIBLOCK + // Evolve solution in a multiblock framework by desired number of steps + void Evolve_MultiBlock(int multiblock_step, int max_block_step); +#endif + // Tag cells for refinement void ErrorEst(int lev, amrex::TagBoxArray& tags, amrex::Real time, int ngrow) @@ -150,6 +159,11 @@ public: void ReadCheckpointFile(); +#ifdef ERF_AMR_WIND_MULTIBLOCK + void SetMultiBlockPointer(MultiBlockContainer* mbc) { m_sim.set_mbc(mbc); } + void set_read_erf(ReadERFFunction fcn) { m_sim.set_read_erf(fcn); } +#endif + private: // // member variables diff --git a/amr-wind/incflo.cpp b/amr-wind/incflo.cpp index 2bfaa16e30..c3fbaf58f4 100644 --- a/amr-wind/incflo.cpp +++ b/amr-wind/incflo.cpp @@ -23,6 +23,12 @@ incflo::incflo() // constructor. No valid BoxArray and DistributionMapping have been defined. // But the arrays for them have been resized. +#ifdef ERF_AMR_WIND_MULTIBLOCK + amrex::Print() << std::endl + << "AMR-Wind is initializing.. " << std::endl + << std::endl; +#endif + // Check if dry run is requested and set up if so CheckAndSetUpDryRun(); diff --git a/amr-wind/utilities/index_operations.H b/amr-wind/utilities/index_operations.H index 49182fa36f..7968a4a28f 100644 --- a/amr-wind/utilities/index_operations.H +++ b/amr-wind/utilities/index_operations.H @@ -9,8 +9,9 @@ namespace amr_wind::utils { //! Return closest index (from lower) of value in vector -AMREX_FORCE_INLINE int -closest_index(const amrex::Vector& vec, const amrex::Real value) +//! lbound version is required for ERF coupling +AMREX_FORCE_INLINE int closest_index_ubound( + const amrex::Vector& vec, const amrex::Real value) { auto const it = std::upper_bound(vec.begin(), vec.end(), value); AMREX_ALWAYS_ASSERT(it != vec.end()); @@ -19,6 +20,18 @@ closest_index(const amrex::Vector& vec, const amrex::Real value) return std::max(idx - 1, 0); } +AMREX_FORCE_INLINE int closest_index_lbound( + const amrex::Vector& vec, const amrex::Real value) +{ + amrex::Real one_minus_eps = 1.0 - 1.e-8; + auto const it = + std::lower_bound(vec.begin(), vec.end(), one_minus_eps * value); + AMREX_ALWAYS_ASSERT(it != vec.end()); + + const int idx = static_cast(std::distance(vec.begin(), it)); + return std::max(idx - 1, 0); +} + //! Return indices perpendicular to normal template > AMREX_FORCE_INLINE T perpendicular_idx(const int normal) diff --git a/amr-wind/wind_energy/ABLBoundaryPlane.H b/amr-wind/wind_energy/ABLBoundaryPlane.H index 0a6d8b5813..57ad7c8321 100644 --- a/amr-wind/wind_energy/ABLBoundaryPlane.H +++ b/amr-wind/wind_energy/ABLBoundaryPlane.H @@ -7,6 +7,10 @@ #include "amr-wind/utilities/ncutils/nc_interface.H" #include +#ifdef ERF_AMR_WIND_MULTIBLOCK +#include "amr-wind/wind_energy/ABLReadERFFcn.H" +class MultiBlockContainer; +#endif namespace amr_wind { enum struct io_mode { output, input, undefined }; @@ -57,7 +61,8 @@ public: const int lev, const Field* /*fld*/, const amrex::Real time, - const amrex::Vector& /*times*/); + const amrex::Vector& /*times*/, + const bool erf_multiblock = false); void interpolate(const amrex::Real /*time*/); bool is_populated(amrex::Orientation /*ori*/) const; @@ -158,11 +163,24 @@ public: io_mode mode() const { return m_io_mode; } +#ifdef ERF_AMR_WIND_MULTIBLOCK + MultiBlockContainer* mbc() { return *m_mbc; } +#endif + private: const amr_wind::SimTime& m_time; const FieldRepo& m_repo; const amrex::AmrCore& m_mesh; +#ifdef ERF_AMR_WIND_MULTIBLOCK + // pointer to pointer : when ABL boundary plane gets initialized, amr-wind + // CFDsim does not yet have the up to date pointer to the mbc or the + // read_erf function, be careful: if this is used before amr-wind gets the + // mbc pointer set bad things will happen + MultiBlockContainer** m_mbc; + ReadERFFunction* m_read_erf{nullptr}; +#endif + #ifdef AMR_WIND_USE_NETCDF void write_data( const ncutils::NCGroup& grp, diff --git a/amr-wind/wind_energy/ABLBoundaryPlane.cpp b/amr-wind/wind_energy/ABLBoundaryPlane.cpp index c9422739ed..aef25207a2 100644 --- a/amr-wind/wind_energy/ABLBoundaryPlane.cpp +++ b/amr-wind/wind_energy/ABLBoundaryPlane.cpp @@ -77,7 +77,7 @@ void InletData::read_data( const size_t nc = fld->num_comp(); const int nstart = m_components[static_cast(fld->id())]; - const int idx = utils::closest_index(times, time); + const int idx = utils::closest_index_ubound(times, time); const int idxp1 = idx + 1; m_tn = times[idx]; m_tnp1 = times[idxp1]; @@ -144,13 +144,22 @@ void InletData::read_data_native( const int lev, const Field* fld, const amrex::Real time, - const amrex::Vector& times) + const amrex::Vector& times, + const bool erf_multiblock) { const size_t nc = fld->num_comp(); const int nstart = static_cast(m_components[static_cast(fld->id())]); - const int idx = utils::closest_index(times, time); + int idx; + if (erf_multiblock) { + // the time is often equal to the new time for multiblock + // hence the need for a lower-bound version of this function + // otherwise it will abort + idx = utils::closest_index_lbound(times, time); + } else { + idx = utils::closest_index_ubound(times, time); + } const int idxp1 = idx + 1; m_tn = times[idx]; @@ -158,7 +167,9 @@ void InletData::read_data_native( auto ori = oit(); - AMREX_ALWAYS_ASSERT(((m_tn <= time) && (time <= m_tnp1))); + amrex::Real one_plus_eps = 1.0 + 1.e-8; + AMREX_ALWAYS_ASSERT( + ((m_tn <= one_plus_eps * time) && (time <= one_plus_eps * m_tnp1))); AMREX_ALWAYS_ASSERT(fld->num_comp() == bndry_n[ori].nComp()); AMREX_ASSERT(bndry_n[ori].boxArray() == bndry_np1[ori].boxArray()); @@ -244,7 +255,13 @@ bool InletData::is_populated(amrex::Orientation ori) const } ABLBoundaryPlane::ABLBoundaryPlane(CFDSim& sim) - : m_time(sim.time()), m_repo(sim.repo()), m_mesh(sim.mesh()) + : m_time(sim.time()) + , m_repo(sim.repo()) + , m_mesh(sim.mesh()) +#ifdef ERF_AMR_WIND_MULTIBLOCK + , m_mbc(sim.mbc()) + , m_read_erf(sim.get_read_erf()) +#endif { amrex::ParmParse pp("ABL"); int pp_io_mode = -1; @@ -281,7 +298,8 @@ ABLBoundaryPlane::ABLBoundaryPlane(CFDSim& sim) } #endif - if (!(m_out_fmt == "native" || m_out_fmt == "netcdf")) { + if (!((m_out_fmt == "native") || (m_out_fmt == "netcdf") || + (m_out_fmt == "erf-multiblock"))) { amrex::Print() << "Warning: boundary output format not recognized, " "changing to native format" << std::endl; @@ -336,6 +354,10 @@ void ABLBoundaryPlane::initialize_data() "ABLBoundaryPlane: invalid variable requested: " + fname); } } + if ((m_io_mode == io_mode::output) && (m_out_fmt == "erf-multiblock")) { + amrex::Abort( + "ABLBoundaryPlane: can't output data in erf-multiblock mode"); + } } void ABLBoundaryPlane::write_header() @@ -748,6 +770,35 @@ void ABLBoundaryPlane::read_header() m_in_data.define_level_data(ori, pbx, nc); } } + } else if (m_out_fmt == "erf-multiblock") { + + m_in_times.push_back(-1.0e13); // create space for storing time at erf + // old and new timestep + m_in_times.push_back(-1.0e13); + + int nc = 0; + for (auto* fld : m_fields) { + m_in_data.component(static_cast(fld->id())) = nc; + nc += fld->num_comp(); + } + + // FIXME: need to generalize to lev > 0 somehow + const int lev = 0; + for (amrex::OrientationIter oit; oit != nullptr; ++oit) { + auto ori = oit(); + // FIXME: would be safer and less storage to not allocate all of + // these but we do not use m_planes for input and need to detect + // mass inflow from field bcs same for define level data below + m_in_data.define_plane(ori); + const amrex::Box& minBox = m_mesh.boxArray(lev).minimalBox(); + amrex::IntVect plo(minBox.loVect()); + amrex::IntVect phi(minBox.hiVect()); + const int normal = ori.coordDir(); + plo[normal] = ori.isHigh() ? minBox.hiVect()[normal] + 1 : -1; + phi[normal] = ori.isHigh() ? minBox.hiVect()[normal] + 1 : -1; + const amrex::Box pbx(plo, phi); + m_in_data.define_level_data(ori, pbx, nc); + } } } @@ -758,6 +809,19 @@ void ABLBoundaryPlane::read_file() return; } +#ifdef ERF_AMR_WIND_MULTIBLOCK + if (m_out_fmt == "erf-multiblock") { + // m_read_erf = sim.get_read_erf(); + ReadERFFunction read_erf = *m_read_erf; + if (read_erf) { + read_erf(m_time, m_in_times, m_in_data, m_fields, mbc()); + } else { + amrex::Abort("read_erf function is undefined."); + } + return; + } +#endif + // populate planes and interpolate const amrex::Real time = m_time.new_time(); AMREX_ALWAYS_ASSERT((m_in_times[0] <= time) && (time < m_in_times.back())); @@ -796,7 +860,7 @@ void ABLBoundaryPlane::read_file() if (m_out_fmt == "native") { - const int index = utils::closest_index(m_in_times, time); + const int index = utils::closest_index_ubound(m_in_times, time); const int t_step1 = m_in_timesteps[index]; const int t_step2 = m_in_timesteps[index + 1]; diff --git a/amr-wind/wind_energy/ABLFieldInit.H b/amr-wind/wind_energy/ABLFieldInit.H index 0fe98676b6..08650992be 100644 --- a/amr-wind/wind_energy/ABLFieldInit.H +++ b/amr-wind/wind_energy/ABLFieldInit.H @@ -47,6 +47,20 @@ public: void init_tke(const amrex::Geometry& geom, amrex::MultiFab& tke) const; private: + // ABL-with-bubble + + //! Initial bubble location + amrex::Vector m_bubble_loc{{0.25, 0.25, 0.5}}; + + //! Initial bubble radius + amrex::Real m_bubble_radius{0.1}; + + //! Initial bubble + amrex::Real m_bubble_temp_ratio{1.1}; + + //! Whether or not to have temperature bubble + bool m_use_bubble{0}; + //! Initial velocity components amrex::Vector m_vel; diff --git a/amr-wind/wind_energy/ABLFieldInit.cpp b/amr-wind/wind_energy/ABLFieldInit.cpp index bbddad29b0..0846eecd2f 100644 --- a/amr-wind/wind_energy/ABLFieldInit.cpp +++ b/amr-wind/wind_energy/ABLFieldInit.cpp @@ -24,6 +24,17 @@ void ABLFieldInit::initialize_from_inputfile() { amrex::ParmParse pp_abl("ABL"); + // ABL-with-bubble + pp_abl.query("use_bubble", m_use_bubble); + if (m_use_bubble) { + amrex::Print() << "Initializing with bubble" << std::endl; + pp_abl.getarr("bubble_loc", m_bubble_loc); + pp_abl.query("bubble_radius", m_bubble_radius); + pp_abl.query("bubble_temp_ratio", m_bubble_temp_ratio); + } else { + amrex::Print() << "Not initializing with bubble" << std::endl; + } + // Temperature variation as a function of height pp_abl.getarr("temperature_heights", m_theta_heights); pp_abl.getarr("temperature_values", m_theta_values); @@ -219,8 +230,14 @@ void ABLFieldInit::operator()( const amrex::Real bottom_v_vel = m_bottom_vel[1]; const amrex::Real bottom_w_vel = m_bottom_vel[2]; + const amrex::Real bcx = m_bubble_loc[0]; + const amrex::Real bcy = m_bubble_loc[1]; + const amrex::Real bcz = m_bubble_loc[2]; + amrex::ParallelFor( vbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { + const amrex::Real x = problo[0] + (i + 0.5) * dx[0]; + const amrex::Real y = problo[1] + (j + 0.5) * dx[1]; const amrex::Real z = problo[2] + (k + 0.5) * dx[2]; density(i, j, k) = rho_init; @@ -240,6 +257,17 @@ void ABLFieldInit::operator()( temperature(i, j, k, 0) += theta; + amrex::Real ratio = 1.0; + if (m_use_bubble) { + amrex::Real radius = std::sqrt( + (x - bcx) * (x - bcx) + (y - bcy) * (y - bcy) + + (z - bcz) * (z - bcz)); + ratio = 1.0 + (m_bubble_temp_ratio - 1.0) * + exp(-0.5 * radius * radius / + (m_bubble_radius * m_bubble_radius)); + } + temperature(i, j, k, 0) *= ratio; + if (linear_profile) { velocity(i, j, k, 0) = bottom_u_vel + z * (top_u_vel - bottom_u_vel) / diff --git a/amr-wind/wind_energy/ABLReadERFFcn.H b/amr-wind/wind_energy/ABLReadERFFcn.H new file mode 100644 index 0000000000..9274246dc8 --- /dev/null +++ b/amr-wind/wind_energy/ABLReadERFFcn.H @@ -0,0 +1,17 @@ +#ifndef ABLREADERFFCN_H +#define ABLREADERFFCN_H +#include + +class MultiBlockContainer; +namespace amr_wind { +class InletData; +} + +using ReadERFFunction = std::function&, + amr_wind::InletData&, + const amrex::Vector&, + MultiBlockContainer*)>; + +#endif /* ABLREADERFFCN_H */ diff --git a/cmake/amr-wind-utils.cmake b/cmake/amr-wind-utils.cmake index 97dc415485..674fbaa167 100644 --- a/cmake/amr-wind-utils.cmake +++ b/cmake/amr-wind-utils.cmake @@ -28,8 +28,8 @@ endfunction(set_cuda_build_properties) macro(init_amrex) if (${AMR_WIND_USE_INTERNAL_AMREX}) - set(AMREX_SUBMOD_LOCATION "${CMAKE_SOURCE_DIR}/submods/amrex") - include(${CMAKE_SOURCE_DIR}/cmake/set_amrex_options.cmake) + set(AMREX_SUBMOD_LOCATION "${PROJECT_SOURCE_DIR}/submods/amrex") + include(${PROJECT_SOURCE_DIR}/cmake/set_amrex_options.cmake) list(APPEND CMAKE_MODULE_PATH "${AMREX_SUBMOD_LOCATION}/Tools/CMake") add_subdirectory(${AMREX_SUBMOD_LOCATION}) set(FCOMPARE_EXE ${CMAKE_BINARY_DIR}/submods/amrex/Tools/Plotfile/amrex_fcompare @@ -70,8 +70,8 @@ endmacro(init_amrex) macro(init_amrex_hydro) if (${AMR_WIND_USE_INTERNAL_AMREX_HYDRO}) - set(AMREX_HYDRO_SUBMOD_LOCATION "${CMAKE_SOURCE_DIR}/submods/AMReX-Hydro") - include(${CMAKE_SOURCE_DIR}/cmake/set_amrex_hydro_options.cmake) + set(AMREX_HYDRO_SUBMOD_LOCATION "${PROJECT_SOURCE_DIR}/submods/AMReX-Hydro") + include(${PROJECT_SOURCE_DIR}/cmake/set_amrex_hydro_options.cmake) add_subdirectory(${AMREX_HYDRO_SUBMOD_LOCATION}) else() set(CMAKE_PREFIX_PATH ${AMReX-Hydro_DIR} ${CMAKE_PREFIX_PATH}) @@ -124,7 +124,7 @@ macro(init_code_checks) COMMAND ${CMAKE_COMMAND} -E make_directory cppcheck # cppcheck ignores -isystem directories, so we change them to regular -I include directories (with no spaces either) COMMAND sed "s/isystem /I/g" ${CMAKE_BINARY_DIR}/compile_commands.json > cppcheck_compile_commands.json - COMMAND ${CPPCHECK_EXE} --template=gcc --inline-suppr --suppress=unusedFunction --suppress=useStlAlgorithm --suppress=missingIncludeSystem --std=c++17 --language=c++ --enable=all --project=cppcheck_compile_commands.json -i ${CMAKE_SOURCE_DIR}/submods/amrex/Src -i ${CMAKE_SOURCE_DIR}/submods/AMReX-Hydro -i ${CMAKE_SOURCE_DIR}/submods/Waves2AMR -i ${CMAKE_SOURCE_DIR}/submods/googletest --output-file=cppcheck-full-report.txt -j ${NP} + COMMAND ${CPPCHECK_EXE} --template=gcc --inline-suppr --suppress=unusedFunction --suppress=useStlAlgorithm --suppress=missingIncludeSystem --std=c++17 --language=c++ --enable=all --project=cppcheck_compile_commands.json -i ${PROJECT_SOURCE_DIR}/submods/amrex/Src -i ${PROJECT_SOURCE_DIR}/submods/AMReX-Hydro -i ${PROJECT_SOURCE_DIR}/submods/Waves2AMR -i ${PROJECT_SOURCE_DIR}/submods/googletest --output-file=cppcheck-full-report.txt -j ${NP} COMMENT "Run cppcheck on project compile_commands.json" BYPRODUCTS cppcheck-full-report.txt WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/cppcheck