GlobalSparsityPattern computeSparsityPatternNonPETSc( NumLib::LocalToGlobalIndexMap const& dof_table, MeshLib::Mesh const& mesh) { MeshLib::NodeAdjacencyTable node_adjacency_table; node_adjacency_table.createTable(mesh.getNodes()); // A mapping mesh node id -> global indices // It acts as a cache for dof table queries. std::vector<std::vector<GlobalIndexType>> global_idcs; global_idcs.reserve(mesh.getNumberOfNodes()); for (std::size_t n = 0; n < mesh.getNumberOfNodes(); ++n) { MeshLib::Location l(mesh.getID(), MeshLib::MeshItemType::Node, n); global_idcs.push_back(dof_table.getGlobalIndices(l)); } GlobalSparsityPattern sparsity_pattern(dof_table.dofSizeWithGhosts()); // Map adjacent mesh nodes to "adjacent global indices". for (std::size_t n = 0; n < mesh.getNumberOfNodes(); ++n) { unsigned n_connected_dof = 0; for (auto an : node_adjacency_table.getAdjacentNodes(n)) n_connected_dof += global_idcs[an].size(); for (auto global_index : global_idcs[n]) sparsity_pattern[global_index] = n_connected_dof; } return sparsity_pattern; }
NeumannBc::NeumannBc( NeumannBcConfig const& bc, unsigned const integration_order, NumLib::LocalToGlobalIndexMap const& local_to_global_index_map, int const variable_id, int const component_id) : _function(*bc.getFunction()), _integration_order(integration_order) { assert(component_id < static_cast<int>(local_to_global_index_map.getNumberOfComponents())); // deep copy because the neumann bc config destroys the elements. std::transform(bc.elementsBegin(), bc.elementsEnd(), std::back_inserter(_elements), std::mem_fn(&MeshLib::Element::clone)); std::vector<MeshLib::Node*> nodes = MeshLib::getUniqueNodes(_elements); auto const& mesh_subsets = local_to_global_index_map.getMeshSubsets(variable_id, component_id); // TODO extend the node intersection to all parts of mesh_subsets, i.e. // to each of the MeshSubset in the mesh_subsets. _mesh_subset_all_nodes = mesh_subsets.getMeshSubset(0).getIntersectionByNodes(nodes); std::unique_ptr<MeshLib::MeshSubsets> all_mesh_subsets{ new MeshLib::MeshSubsets{_mesh_subset_all_nodes}}; // Create local DOF table from intersected mesh subsets for the given // variable and component ids. _local_to_global_index_map.reset( local_to_global_index_map.deriveBoundaryConstrainedMap( variable_id, component_id, std::move(all_mesh_subsets), _elements)); }
std::unique_ptr<PythonBoundaryCondition> createPythonBoundaryCondition( BaseLib::ConfigTree const& config, MeshLib::Mesh const& boundary_mesh, NumLib::LocalToGlobalIndexMap const& dof_table, std::size_t bulk_mesh_id, int const variable_id, int const component_id, unsigned const integration_order, unsigned const shapefunction_order, unsigned const global_dim) { //! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__type} config.checkConfigParameter("type", "Python"); //! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__Python__bc_object} auto const bc_object = config.getConfigParameter<std::string>("bc_object"); //! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__Python__flush_stdout} auto const flush_stdout = config.getConfigParameter("flush_stdout", false); // Evaluate Python code in scope of main module pybind11::object scope = pybind11::module::import("__main__").attr("__dict__"); if (!scope.contains(bc_object)) OGS_FATAL( "Function `%s' is not defined in the python script file, or there " "was no python script file specified.", bc_object.c_str()); auto* bc = scope[bc_object.c_str()] .cast<PythonBoundaryConditionPythonSideInterface*>(); if (variable_id >= static_cast<int>(dof_table.getNumberOfVariables()) || component_id >= dof_table.getNumberOfVariableComponents(variable_id)) { OGS_FATAL( "Variable id or component id too high. Actual values: (%d, %d), " "maximum values: (%d, %d).", variable_id, component_id, dof_table.getNumberOfVariables(), dof_table.getNumberOfVariableComponents(variable_id)); } // In case of partitioned mesh the boundary could be empty, i.e. there is no // boundary condition. #ifdef USE_PETSC // This can be extracted to createBoundaryCondition() but then the config // parameters are not read and will cause an error. // TODO (naumov): Add a function to ConfigTree for skipping the tags of the // subtree and move the code up in createBoundaryCondition(). if (boundary_mesh.getDimension() == 0 && boundary_mesh.getNumberOfNodes() == 0 && boundary_mesh.getNumberOfElements() == 0) { return nullptr; } #endif // USE_PETSC return std::make_unique<PythonBoundaryCondition>( PythonBoundaryConditionData{ bc, dof_table, bulk_mesh_id, dof_table.getGlobalComponent(variable_id, component_id), boundary_mesh}, integration_order, shapefunction_order, global_dim, flush_stdout); }
// TODO Copied from VectorMatrixAssembler. Could be provided by the DOF table. inline NumLib::LocalToGlobalIndexMap::RowColumnIndices getRowColumnIndices_(std::size_t const id, NumLib::LocalToGlobalIndexMap const& dof_table, std::vector<GlobalIndexType>& indices) { assert(dof_table.size() > id); indices.clear(); // Local matrices and vectors will always be ordered by component, // no matter what the order of the global matrix is. for (unsigned c = 0; c < dof_table.getNumberOfComponents(); ++c) { auto const& idcs = dof_table(id, c).rows; indices.reserve(indices.size() + idcs.size()); indices.insert(indices.end(), idcs.begin(), idcs.end()); } return NumLib::LocalToGlobalIndexMap::RowColumnIndices(indices, indices); }
// TODO that essentially duplicates code which is also present in ProcessOutput. double getNodalValue(GlobalVector const& x, MeshLib::Mesh const& mesh, NumLib::LocalToGlobalIndexMap const& dof_table, std::size_t const node_id, std::size_t const global_component_id) { MeshLib::Location const l{mesh.getID(), MeshLib::MeshItemType::Node, node_id}; auto const index = dof_table.getLocalIndex( l, global_component_id, x.getRangeBegin(), x.getRangeEnd()); return x.get(index); }
void DirichletBoundaryConditionWithinTimeInterval::config( NumLib::LocalToGlobalIndexMap const& dof_table_bulk) { checkParametersOfDirichletBoundaryCondition(_bc_mesh, dof_table_bulk, _variable_id, _component_id); std::vector<MeshLib::Node*> const& bc_nodes = _bc_mesh.getNodes(); MeshLib::MeshSubset bc_mesh_subset(_bc_mesh, bc_nodes); // Create local DOF table from the BC mesh subset for the given variable // and component id. _dof_table_boundary.reset(dof_table_bulk.deriveBoundaryConstrainedMap( _variable_id, {_component_id}, std::move(bc_mesh_subset))); }
GlobalSparsityPattern computeSparsityPatternPETSc( NumLib::LocalToGlobalIndexMap const& dof_table, MeshLib::Mesh const& mesh) { assert(dynamic_cast<MeshLib::NodePartitionedMesh const*>(&mesh)); auto const& npmesh = *static_cast<MeshLib::NodePartitionedMesh const*>(&mesh); auto const max_nonzeroes = dof_table.getNumberOfComponents() * npmesh.getMaximumNConnectedNodesToNode(); // The sparsity pattern is misused here in the sense that it will only // contain a single value. return GlobalSparsityPattern(1, max_nonzeroes); }
LocalLinearLeastSquaresExtrapolator::LocalLinearLeastSquaresExtrapolator( NumLib::LocalToGlobalIndexMap const& dof_table) : _dof_table_single_component(dof_table) { /* Note in case the following assertion fails: * If you copied the extrapolation code, for your processes from * somewhere, note that the code from the groundwater flow process might * not suit your needs: It is a special case and is therefore most * likely too simplistic. You better adapt the extrapolation code from * some more advanced process, like the TES process. */ if (dof_table.getNumberOfComponents() != 1) OGS_FATAL( "The d.o.f. table passed must be for one variable that has " "only one component!"); }
void ProcessVariable::createBoundaryConditionsForDeactivatedSubDomains( const NumLib::LocalToGlobalIndexMap& dof_table, const int variable_id, std::vector<std::unique_ptr<ParameterBase>> const& parameters, std::vector<std::unique_ptr<BoundaryCondition>>& bcs) { auto& parameter = findParameter<double>( DeactivatedSubdomain::name_of_paramater_of_zero, parameters, 1); for (auto const& deactivated_subdomain : _deactivated_subdomains) { auto const& deactivated_subdomain_meshes = deactivated_subdomain->deactivated_subdomain_meshes; for (auto const& deactivated_subdomain_mesh : deactivated_subdomain_meshes) { for (int component_id = 0; component_id < dof_table.getNumberOfComponents(); component_id++) { // Copy the time interval. std::unique_ptr<BaseLib::TimeInterval> time_interval = std::make_unique<BaseLib::TimeInterval>( *deactivated_subdomain->time_interval); auto bc = std::make_unique< DirichletBoundaryConditionWithinTimeInterval>( std::move(time_interval), parameter, *(deactivated_subdomain_mesh->mesh), deactivated_subdomain_mesh->inactive_nodes, dof_table, variable_id, component_id); #ifdef USE_PETSC // TODO: make it work under PETSc too. if (bc == nullptr) { continue; } #endif // USE_PETSC bcs.push_back(std::move(bc)); } } } }