module; #include #include #include #include #include export module mean_field:utils.blocks; export namespace mean_field::utils::blocks { inline constexpr int dynamic_block_size = -1; struct block { }; struct residual_block_base : block { static constexpr int static_block_size = dynamic_block_size; }; struct value_block_base : block { static constexpr int static_block_size = dynamic_block_size; }; struct term { }; struct field { }; template struct block_row { }; template struct residual_block final : residual_block_base { static constexpr int index = index_value; // ReSharper disable once CppNonExplicitConversionOperator constexpr operator int() const noexcept { return index; } }; template struct value_block final : value_block_base { static constexpr int index = index_value; // ReSharper disable once CppNonExplicitConversionOperator constexpr operator int() const noexcept { return index; } }; struct density final : field { struct mass final : term { struct value final : value_block_base { }; struct residual final : residual_block_base { }; }; static inline constexpr mass mass_term{}; }; struct displacement final : field { struct geometry final : term { struct value final : value_block_base { }; struct residual final : residual_block_base { }; }; static inline constexpr geometry geometry_term{}; }; struct gravity final : field { struct gradient final : term { struct value final : value_block_base { }; struct residual final : residual_block_base { }; }; struct poisson final : term { struct value final : value_block_base { }; struct residual final : residual_block_base { }; }; static inline constexpr gradient gradient_term{}; static inline constexpr poisson poisson_term{}; }; struct enthalpy final : field { struct specific final : term { struct value final : value_block_base { }; struct residual final : residual_block_base { }; }; static inline constexpr specific specific_term{}; }; struct barotropic_constant final : field { struct mass_normalization final : term { struct value final : value_block_base { static constexpr int static_block_size = 1; }; struct residual final : residual_block_base { static constexpr int static_block_size = 1; }; }; static inline constexpr mass_normalization mass_normalization_term{}; }; inline constexpr density density_field{}; inline constexpr displacement displacement_field{}; inline constexpr gravity gravity_field{}; inline constexpr enthalpy enthalpy_field{}; inline constexpr barotropic_constant barotropic_constant_field{}; template struct type_list { static constexpr int size = sizeof...(Types); }; template struct contains_type; template struct contains_type> : std::false_type { }; template struct contains_type> : std::conditional_t< std::is_same_v, std::true_type, contains_type>> { }; template inline constexpr bool contains_type_v = contains_type::value; template struct type_count; template struct type_count> : std::integral_constant { }; template struct type_count> : std::integral_constant< int, (std::is_same_v ? 1 : 0) + type_count>::value> { }; template inline constexpr int type_count_v = type_count::value; template struct types_are_unique; template struct types_are_unique> : std::bool_constant< ((type_count_v> == 1) && ...)> { }; template inline constexpr bool types_are_unique_v = types_are_unique::value; template struct block_row_traits { using residual = void; using values = type_list<>; static constexpr int value_count = 0; static constexpr bool is_block_row = false; }; template struct block_row_traits> { using residual = Residual; using values = type_list; static constexpr int value_count = sizeof...(Values); static constexpr bool is_block_row = true; }; template struct type_index; template struct type_index> { static constexpr int value = 0; }; template struct type_index> { static constexpr int value = 1 + type_index>::value; }; template inline constexpr int type_index_v = type_index::value; template struct block_form { using value_blocks = ValueBlocks; using residual_blocks = ResidualBlocks; static constexpr int value_block_count = ValueBlocks::size; static constexpr int residual_block_count = ResidualBlocks::size; }; template struct block_form_is_valid : std::false_type { }; template struct block_form_is_valid< block_form, type_list>> : std::bool_constant< (std::is_base_of_v && ...) && (std::is_base_of_v && ...) && types_are_unique_v> && types_are_unique_v>> { }; template inline constexpr bool block_form_is_valid_v = block_form_is_valid
::value; template struct block_row_is_valid : std::false_type { }; template < typename Residual, typename... Values, typename ValueBlocks, typename ResidualBlocks> struct block_row_is_valid< block_row, ValueBlocks, ResidualBlocks> : std::bool_constant< std::is_base_of_v && contains_type_v && ((std::is_base_of_v && contains_type_v) && ...) && types_are_unique_v>> { }; template struct row_residual_list; template struct row_residual_list> { using type = type_list::residual...>; }; template using row_residual_list_t = typename row_residual_list::type; template struct jacobian_form_is_valid : std::false_type { }; template struct jacobian_form_is_valid< block_form, type_list>, type_list> { using form_type = block_form, type_list>; using value_blocks = type_list; using residual_blocks = type_list; using rows = type_list; static constexpr bool value = block_form_is_valid_v && (block_row_is_valid::value && ...) && std::is_same_v, residual_blocks>; }; template inline constexpr bool jacobian_form_is_valid_v = jacobian_form_is_valid::value; template concept valid_jacobian_form = jacobian_form_is_valid_v; template struct has_jacobian_coupling; template struct has_jacobian_coupling> : std::false_type { }; template < typename Residual, typename Value, typename RowResidual, typename... RowValues, typename... RemainingRows> struct has_jacobian_coupling< Residual, Value, type_list, RemainingRows...>> : std::conditional_t< std::is_same_v, std::bool_constant<(std::is_same_v || ...)>, has_jacobian_coupling< Residual, Value, type_list>> { }; template inline constexpr bool has_jacobian_coupling_v = has_jacobian_coupling::value; template < typename Form, typename Term> consteval auto get_value_block(const Term &) { using value_type = typename Term::value; constexpr int index = type_index_v; return value_block{}; } template < typename Form, typename Term> consteval auto get_residual_block(const Term &) { using residual_type = typename Term::residual; constexpr int index = type_index_v; return residual_block{}; } template class form_layout { public: form_layout( const std::array< int, Form::value_block_count> &value_sizes, const std::array< int, Form::residual_block_count> &residual_sizes ) { build_offsets( m_value_offsets, value_sizes, typename Form::value_blocks{} ); build_offsets( m_residual_offsets, residual_sizes, typename Form::residual_blocks{} ); } template [[nodiscard]] int size(value_block) const { return m_value_offsets[index + 1] - m_value_offsets[index]; } template [[nodiscard]] int size(residual_block) const { return m_residual_offsets[index + 1] - m_residual_offsets[index]; } template [[nodiscard]] int offset(value_block) const { return m_value_offsets[index]; } template [[nodiscard]] int offset(residual_block) const { return m_residual_offsets[index]; } [[nodiscard]] const mfem::Array &value_offsets() const noexcept { return m_value_offsets; } [[nodiscard]] const mfem::Array &residual_offsets() const noexcept { return m_residual_offsets; } private: template [[nodiscard]] static int resolve_block_size(const int requested_size) { if constexpr (BlockType::static_block_size == dynamic_block_size) { return requested_size; } else { if (requested_size != BlockType::static_block_size) { throw std::invalid_argument( "A statically sized block was given an " "incompatible runtime size." ); } return BlockType::static_block_size; } } template static void build_offsets( mfem::Array &offsets, const std::array< int, sizeof...(BlockTypes)> &requested_sizes, type_list ) { offsets.SetSize(sizeof...(BlockTypes) + 1); offsets[0] = 0; int block_index = 0; ((offsets[block_index + 1] = offsets[block_index] + resolve_block_size(requested_sizes[block_index]), ++block_index), ...); } mfem::Array m_value_offsets; mfem::Array m_residual_offsets; }; using gravity_field_form = block_form< type_list< density::mass::value, displacement::geometry::value, gravity::gradient::value, gravity::poisson::value>, type_list>; using gravity_jacobian_form = type_list< block_row< gravity::gradient::residual, gravity::gradient::value, gravity::poisson::value, displacement::geometry::value>, block_row< gravity::poisson::residual, gravity::gradient::value, density::mass::value, displacement::geometry::value>>; // Columns: // [rho, d, g, Phi, h, C] // // Rows: // [R_g, R_Phi, R_rho, R_d, R_h, R_M] using barotropic_equilibrium_form = block_form< type_list< density::mass::value, displacement::geometry::value, gravity::gradient::value, gravity::poisson::value, enthalpy::specific::value, barotropic_constant::mass_normalization::value>, type_list< gravity::gradient::residual, gravity::poisson::residual, density::mass::residual, displacement::geometry::residual, enthalpy::specific::residual, barotropic_constant::mass_normalization::residual>>; using barotropic_equilibrium_jacobian_form = type_list< // R_g(g, Phi, d) block_row< gravity::gradient::residual, gravity::gradient::value, gravity::poisson::value, displacement::geometry::value>, // R_Phi(g, rho, d) block_row< gravity::poisson::residual, gravity::gradient::value, density::mass::value, displacement::geometry::value>, // R_rho(rho, h, d) block_row< density::mass::residual, density::mass::value, enthalpy::specific::value, displacement::geometry::value>, // R_d(d, h) block_row< displacement::geometry::residual, displacement::geometry::value, enthalpy::specific::value>, // R_h(h, Phi, d, C) block_row< enthalpy::specific::residual, enthalpy::specific::value, gravity::poisson::value, displacement::geometry::value, barotropic_constant::mass_normalization::value>, // R_M(rho, d) block_row< barotropic_constant::mass_normalization::residual, density::mass::value, displacement::geometry::value>>; static_assert(valid_jacobian_form< gravity_field_form, gravity_jacobian_form>); static_assert(valid_jacobian_form< barotropic_equilibrium_form, barotropic_equilibrium_jacobian_form>); } // namespace mean_field::utils::blocks