2323#include < concepts>
2424#include < limits>
2525#include < numeric>
26+ #include < optional>
27+ #include < stdexcept>
2628
2729#define str_macro (X ) #X
2830#define str (X ) str_macro(X)
@@ -328,10 +330,15 @@ basix::create_tp_element(element::family family, cell::type cell, int degree,
328330 element::lagrange_variant lvariant,
329331 element::dpc_variant dvariant, bool discontinuous)
330332{
331- std::vector<int > dof_ordering = tp_dof_ordering (
333+ std::optional<std:: vector<int > > dof_ordering = tp_dof_ordering (
332334 family, cell, degree, lvariant, dvariant, discontinuous);
335+
336+ if (!dof_ordering.has_value ())
337+ throw std::runtime_error (
338+ " Element does not have tensor product factorisation." );
339+
333340 return create_element<T>(family, cell, degree, lvariant, dvariant,
334- discontinuous, dof_ordering);
341+ discontinuous, * dof_ordering);
335342}
336343// -----------------------------------------------------------------------------
337344template basix::FiniteElement<float >
@@ -342,60 +349,54 @@ basix::create_tp_element(element::family, cell::type, int,
342349 element::lagrange_variant, element::dpc_variant, bool );
343350// -----------------------------------------------------------------------------
344351template <std::floating_point T>
345- std::vector<std::vector<FiniteElement<T>>>
352+ std::optional<std:: vector<std::vector<FiniteElement<T> >>>
346353basix::tp_factors (element::family family, cell::type cell, int degree,
347354 element::lagrange_variant lvariant,
348355 element::dpc_variant dvariant, bool discontinuous,
349356 const std::vector<int >& dof_ordering)
350357{
351- std::vector<int > tp_dofs = tp_dof_ordering (family, cell, degree, lvariant,
352- dvariant, discontinuous);
353- if (!tp_dofs.empty () && tp_dofs == dof_ordering)
358+ std::optional<std::vector<int >> tp_dofs = tp_dof_ordering (
359+ family, cell, degree, lvariant, dvariant, discontinuous);
360+ if (!tp_dofs.has_value () || tp_dofs->empty ()
361+ || tp_dofs.value () != dof_ordering)
362+ return std::nullopt ;
363+
364+ switch (family)
354365 {
355- switch (family)
356- {
357- case element::family::P:
366+ case element::family::P:
367+ {
368+ FiniteElement<T> sub_element
369+ = create_element<T>(element::family::P, cell::type::interval, degree,
370+ lvariant, dvariant, true );
371+ switch (cell)
358372 {
359- FiniteElement<T> sub_element
360- = create_element<T>(element::family::P, cell::type::interval, degree,
361- lvariant, dvariant, true );
362- switch (cell)
363- {
364- case cell::type::quadrilateral:
365- {
366- return {{sub_element, sub_element}};
367- }
368- case cell::type::hexahedron:
369- {
370- return {{sub_element, sub_element, sub_element}};
371- }
372- default :
373- {
374- throw std::runtime_error (" Invalid celltype." );
375- }
376- }
377- break ;
378- }
373+ case cell::type::quadrilateral:
374+ return {{{sub_element, sub_element}}};
375+ case cell::type::hexahedron:
376+ return {{{sub_element, sub_element, sub_element}}};
379377 default :
380- {
381- throw std::runtime_error (" Invalid family." );
382- }
378+ return std::nullopt ;
383379 }
380+ break ;
384381 }
385- throw std::runtime_error (
386- " Element does not have tensor product factorisation." );
382+ default :
383+ return std::nullopt ;
384+ }
385+ // C++ 23:
386+ // std::unreachable()
387+ return std::nullopt ;
387388}
388389// -----------------------------------------------------------------------------
389- template std::vector<std::vector<basix::FiniteElement<float >>>
390+ template std::optional<std:: vector<std::vector<basix::FiniteElement<float > >>>
390391basix::tp_factors (element::family, cell::type, int , element::lagrange_variant,
391392 element::dpc_variant, bool , const std::vector<int >&);
392- template std::vector<std::vector<basix::FiniteElement<double >>>
393+ template std::optional<std:: vector<std::vector<basix::FiniteElement<double > >>>
393394basix::tp_factors (element::family, cell::type, int , element::lagrange_variant,
394395 element::dpc_variant, bool , const std::vector<int >&);
395396// -----------------------------------------------------------------------------
396- std::vector<int > basix::tp_dof_ordering (element::family family, cell::type cell,
397- int degree, element::lagrange_variant ,
398- element::dpc_variant, bool )
397+ std::optional<std:: vector<int >>
398+ basix::tp_dof_ordering (element::family family, cell::type cell, int degree,
399+ element::lagrange_variant, element::dpc_variant, bool )
399400{
400401 std::vector<int > dof_ordering;
401402 std::vector<int > perm;
@@ -488,21 +489,17 @@ std::vector<int> basix::tp_dof_ordering(element::family family, cell::type cell,
488489 break ;
489490 }
490491 default :
491- {
492- }
492+ return std::nullopt ;
493493 }
494494 break ;
495495 }
496496 default :
497- {
498- }
497+ return std::nullopt ;
499498 }
500499
501500 if (perm.size () == 0 )
502- {
503- throw std::runtime_error (
504- " Element does not have tensor product factorisation." );
505- }
501+ return std::nullopt ;
502+
506503 dof_ordering.resize (perm.size ());
507504 for (std::size_t i = 0 ; i < perm.size (); ++i)
508505 dof_ordering[perm[i]] = i;
@@ -1037,7 +1034,7 @@ FiniteElement<F>::FiniteElement(
10371034 _embedded_superdegree(embedded_superdegree),
10381035 _embedded_subdegree(embedded_subdegree), _value_shape(value_shape),
10391036 _map_type(map_type), _sobolev_space(sobolev_space),
1040- _discontinuous(discontinuous), _dof_ordering(dof_ordering)
1037+ _discontinuous(discontinuous), _dof_ordering(std::move( dof_ordering) )
10411038{
10421039 // Check that discontinuous elements only have DOFs on interior
10431040 if (discontinuous)
@@ -1055,14 +1052,10 @@ FiniteElement<F>::FiniteElement(
10551052 }
10561053 }
10571054
1058- try
1059- {
1060- _tensor_factors = tp_factors<F>(family, cell_type, degree, lvariant,
1061- dvariant, discontinuous, dof_ordering);
1062- }
1063- catch (...)
1064- {
1065- }
1055+ auto factors = tp_factors<F>(family, cell_type, degree, lvariant, dvariant,
1056+ discontinuous, _dof_ordering);
1057+ if (factors.has_value ())
1058+ _tensor_factors = factors.value ();
10661059
10671060 std::vector<F> wcoeffs_b (wcoeffs.extent (0 ) * wcoeffs.extent (1 ));
10681061 std::copy (wcoeffs.data_handle (), wcoeffs.data_handle () + wcoeffs.size (),
0 commit comments