volume_actions.hpp algorithm array limits optional serif/discretization/blocks/system_layout.hpp serif/backend/mfem/model/system.hpp serif/backend/mfem/operators/volume_application.hpp src/include/serif/backend/mfem/model/computations/interior.hpp src/include/serif/backend/mfem/model/computations/scalar_row.hpp serif serif::model serif::model::backend serif::model::backend::mfem #pragmaonce #include<algorithm> #include<array> #include<limits> #include<optional> #include"serif/discretization/blocks/system_layout.hpp" #include"serif/backend/mfem/model/system.hpp" #include"serif/backend/mfem/operators/volume_application.hpp" namespaceserif::model::backend::mfem{ template<operators::VolumeEquationEquation,typenameSchema,discretization::blocks::SystemLayoutTypeLayout> [[nodiscard]]LinearizedBlockvolume_row_action(std::shared_ptr<constoperators::backend::mfem::VolumeData<Equation,Schema>>data,constLayout&layout,std::optional<ColumnContribution>geometry={}){ usingnamespaceutils::errors; usingnamespaceutils::dependencies; usingKind=discretization::blocks::RepresentedValueKind; usingPlan=operators::EquationPlan<Equation>; namespacevolume=operators::backend::mfem; serif_ensure<SERiFErrorCode::INVALID_ARGUMENT>(data!=nullptr,"Acompletevolumeactionrequiresanacceptedequation."); conststd::size_tcolumns=layout.templatetotal_size<Kind::value>(); serif_ensure<SERiFErrorCode::INVALID_DOF_COUNT>(columns<=static_cast<std::size_t>(std::numeric_limits<int>::max()),"CompletevolumeactionstatecoordinatesexceedMFEM'sintegerrange."); std::array<int,Plan::column_count>offsets; offsets.fill(-1); std::array<::mfem::Vector,Plan::column_count>fields; Plan::for_each_column([&]<typenameColumn>(Column,std::size_tcolumn){ usingField=typenameColumn::term_type; fields[column].SetSize(data->bindings.columns[column]->size()); fields[column]=0.0; ifconstexpr(ContainsKey<Field,typenameLayout::Values>){ serif_ensure<SERiFErrorCode::MATRIX_SHAPE_ERROR>(layout.templatesize<Kind::value,Field>()==static_cast<std::size_t>(fields[column].Size()),"Solvedfieldcoordinatesmustmatchtheacceptedvolumebinding."); offsets[column]=static_cast<int>(layout.templateoffset<Kind::value,Field>()); } }); constintdisplacement_size=data->configuration->discretization.displacement_binding.size(); if(geometry){ constauto&action=geometry->block.action(); serif_ensure<SERiFErrorCode::MATRIX_SHAPE_ERROR>(action->Height()==displacement_size&&geometry->column_offset>=0&&static_cast<std::size_t>(geometry->column_offset)<=columns&&static_cast<std::size_t>(action->Width())<=columns-geometry->column_offset,"Thegeometrycolumnmustmapavalidstateintervalintotheaccepteddisplacementcoefficients."); } returnoperators::backend::mfem::linearized_action(volume::volume_height(*data),static_cast<int>(columns), [data,offsets,fields=std::move(fields),geometry,displacement=::mfem::Vector(displacement_size),geometry_direction=::mfem::Vector{},workspace=volume::Workspace{}](const::mfem::Vector&input,::mfem::Vector&output)mutable{ std::array<const::mfem::Vector*,Plan::column_count>directions; for(std::size_tcolumn=0;column<fields.size();++column){ if(offsets[column]>=0){ std::copy_n(input.GetData()+offsets[column],fields[column].Size(),fields[column].GetData()); } directions[column]=&fields[column]; } displacement=0.0; if(geometry){ geometry_direction.SetSize(geometry->block.action()->Width()); std::copy_n(input.GetData()+geometry->column_offset,geometry_direction.Size(),geometry_direction.GetData()); geometry->block.action()->Mult(geometry_direction,displacement); } if(geometry){ volume::apply_volume_direction(*data,directions,displacement,workspace,output); }else{ volume::apply_volume_direction<true,false>(*data,directions,displacement,workspace,output); } }, [data,offsets,geometry,displacement_size,packed=::mfem::Vector{},displacement_dual=::mfem::Vector(displacement_size),geometry_dual=::mfem::Vector{},workspace=volume::Workspace{}](const::mfem::Vector&input,::mfem::Vector&output)mutable{ volume::apply_jacobian_transpose(*data,input,workspace,packed); intsource=0; for(std::size_tcolumn=0;column<offsets.size();++column){ constintsize=data->bindings.columns[column]->size(); if(offsets[column]>=0){ for(intindex=0;index<size;++index){ output[offsets[column]+index]+=packed[source+index]; } } source+=size; } if(geometry){ std::copy_n(packed.GetData()+source,displacement_size,displacement_dual.GetData()); geometry_dual.SetSize(geometry->block.action()->Width()); geometry_dual=0.0; geometry->block.action()->MultTranspose(displacement_dual,geometry_dual); for(intindex=0;index<geometry_dual.Size();++index){ output[geometry->column_offset+index]+=geometry_dual[index]; } } }); } }//namespaceserif::model::backend::mfem