After looking at example 9 again, I have to ask:
Better yet: is there a way to augment the sparsity pattern without this
function? I've read that I should
"
To do this, you need to cast your matrix to a PetscMatrix, then do
petsc_matrix->mat() to get the PETSc Mat that you can pass to
MatSetOption.
PetscMatrix<Number> * NonlocalStiffness_petsc =
&(this->get_matrix("NonlocalStiffness"));
MatSetOption( NonlocalStiffness_petsc.mat() ,
MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);
"
Suppose I added a sparse matrix "TestMat" to the system. How do I do this,
explicitly?
Thanks!
On Tue, Sep 18, 2018 at 3:40 AM Charlie Talbot <[email protected]> wrote:
> Hi, I modified the files in miscellaneous example 9 to augment the
> sparsity pattern to include elements found using Patch, and I can't seem to
> get this to work, what am I missing? Thanks!
>
> #ifndef AUGMENT_SPARSITY_NONLOCAL_H
> #define AUGMENT_SPARSITY_NONLOCAL_H
>
> #include "libmesh/ghosting_functor.h"
> #include "libmesh/mesh_base.h"
> #include "libmesh/patch.h"
> using libMesh::Elem;
> using libMesh::GhostingFunctor;
> using libMesh::MeshBase;
> using libMesh::boundary_id_type;
> using libMesh::processor_id_type;
>
> // Convenient typedef for a map for (element, side id) --> element neighbor
> typedef std::map<std::pair<const Elem *, unsigned char>, const Elem *>
> ElementSideMap;
>
> // And the inverse map, but without sides in the key
> typedef std::map<const Elem *, const Elem *> ElementMap;
>
> class AugmentSparsityNonlocal : public GhostingFunctor
> {
> private:
>
> /**
> * The Mesh we're calculating on
> */
> MeshBase & _mesh;
>
> /**
> * A map from (lower element ID, side ID) to matching upper element ID.
> Here "lower"
> * and "upper" refer to the lower and upper (wrt +z direction) sides of
> the crack in
> * our mesh.
> */
> ElementSideMap _lower_to_upper;
>
> /**
> * The inverse (ignoring sides) of the above map.
> */
> ElementMap _upper_to_lower;
>
> /**
> * Boundary IDs for the lower and upper faces of the "crack" in the mesh.
> */
> boundary_id_type _crack_boundary_lower, _crack_boundary_upper;
>
> /**
> * Make sure we've been initialized before use
> */
> bool _initialized;
>
> public:
> unsigned int _target_patch_size;
>
> /**
> * Constructor.
> */
> AugmentSparsityNonlocal(MeshBase & mesh,
> unsigned int target_patch_size);
> // boundary_id_type crack_boundary_lower,
> // boundary_id_type crack_boundary_upper);
>
> /**
> * @return a const reference to the lower-to-upper element ID map.
> */
> const ElementSideMap & get_lower_to_upper() const;
>
> /**
> * User-defined function to augment the sparsity pattern.
> */
> virtual void operator() (const MeshBase::const_element_iterator &
> range_begin,
> const MeshBase::const_element_iterator &
> range_end,
> processor_id_type p,
> map_type & coupled_elements) override;
>
> /**
> * Rebuild the cached _lower_to_upper map whenever our Mesh has
> * changed.
> */
> virtual void mesh_reinit () override;
>
> /**
> * Update the cached _lower_to_upper map whenever our Mesh has been
> * redistributed. We'll be lazy and just recalculate from scratch.
> */
> virtual void redistribute () override
> { this->mesh_reinit(); }
>
>
> };
>
> #endif
>
>
>
>
>
>
>
>
>
>
>
>
> // local includes
> #include "augment_sparsity_nonlocal.h"
>
> // libMesh includes
> #include "libmesh/elem.h"
>
> using namespace libMesh;
>
> AugmentSparsityNonlocal::AugmentSparsityNonlocal(MeshBase & mesh,
> unsigned int target_patch_size):
> // boundary_id_type
> crack_boundary_lower,
> // boundary_id_type
> crack_boundary_upper) :
> _mesh(mesh),
> // _crack_boundary_lower(crack_boundary_lower),
> // _crack_boundary_upper(crack_boundary_upper),
> _initialized(false)
> {
> this->mesh_reinit();
> this->_target_patch_size = target_patch_size;
>
> }
>
>
> const ElementSideMap & AugmentSparsityNonlocal::get_lower_to_upper() const
> {
> libmesh_assert(this->_initialized);
> return _lower_to_upper;
> }
>
> void AugmentSparsityNonlocal::mesh_reinit ()
> {
> this->_initialized = true;
>
> // Loop over all elements (not just local elements) to make sure we find
> // "neighbor" elements on opposite sides of the crack.
>
> // Map from (elem, side) to centroid
> std::map<std::pair<const Elem *, unsigned char>, Point> lower_centroids;
> std::map<std::pair<const Elem *, unsigned char>, Point> upper_centroids;
>
> // for (const auto & elem : _mesh.active_element_ptr_range())
> // for (auto side : elem->side_index_range())
> // if (elem->neighbor_ptr(side) == nullptr)
> // {
> // if (_mesh.get_boundary_info().has_boundary_id(elem, side,
> _crack_boundary_lower))
> // {
> // std::unique_ptr<const Elem> side_elem =
> elem->build_side_ptr(side);
>
> // lower_centroids[std::make_pair(elem, side)] =
> side_elem->centroid();
> // }
>
> // if (_mesh.get_boundary_info().has_boundary_id(elem, side,
> _crack_boundary_upper))
> // {
> // std::unique_ptr<const Elem> side_elem =
> elem->build_side_ptr(side);
>
> // upper_centroids[std::make_pair(elem, side)] =
> side_elem->centroid();
> // }
> // }
>
> // If we're doing a reinit on a distributed mesh then we may not see
> // all the centroids, or even a matching number of centroids.
> // std::size_t n_lower_centroids = lower_centroids.size();
> // std::size_t n_upper_centroids = upper_centroids.size();
> // libmesh_assert(n_lower_centroids == n_upper_centroids);
>
> // Clear _lower_to_upper. This map will be used for matrix assembly
> later on.
> _lower_to_upper.clear();
>
> // Clear _upper_to_lower. This map will be used for element ghosting
> // on distributed meshes, communication send_list construction in
> // parallel, and sparsity calculations
> _upper_to_lower.clear();
>
> // We do an N^2 search to find elements with matching centroids. This
> could be optimized,
> // e.g. by first sorting the centroids based on their (x,y,z) location.
> {
> std::map<std::pair<const Elem *, unsigned char>, Point>::iterator it
> = lower_centroids.begin();
> std::map<std::pair<const Elem *, unsigned char>, Point>::iterator
> it_end = lower_centroids.end();
> for ( ; it != it_end; ++it)
> {
> Point lower_centroid = it->second;
>
> // find closest centroid in upper_centroids
> Real min_distance = std::numeric_limits<Real>::max();
>
> std::map<std::pair<const Elem *, unsigned char>, Point>::iterator
> inner_it = upper_centroids.begin();
> std::map<std::pair<const Elem *, unsigned char>, Point>::iterator
> inner_it_end = upper_centroids.end();
>
> for ( ; inner_it != inner_it_end; ++inner_it)
> {
> Point upper_centroid = inner_it->second;
>
> Real distance = (upper_centroid - lower_centroid).norm();
> if (distance < min_distance)
> {
> min_distance = distance;
> _lower_to_upper[it->first] = inner_it->first.first;
> }
> }
>
> // For pairs with local elements, we should have found a
> // matching pair by now.
> const Elem * elem = it->first.first;
> const Elem * neighbor = _lower_to_upper[it->first];
> if (min_distance < TOLERANCE)
> {
> // fill up the inverse map
> _upper_to_lower[neighbor] = elem;
> }
> else
> {
> libmesh_assert_not_equal_to(elem->processor_id(),
> _mesh.processor_id());
> // This must have a false positive; a remote element would
> // have been closer.
> _lower_to_upper.erase(it->first);
> }
> }
>
> // Let's make sure we didn't miss any upper elements either
> // #ifndef NDEBUG
> // std::map<std::pair<const Elem *, unsigned char>, Point>::iterator
> inner_it = upper_centroids.begin();
> // std::map<std::pair<const Elem *, unsigned char>, Point>::iterator
> inner_it_end = upper_centroids.end();
>
> // for ( ; inner_it != inner_it_end; ++inner_it)
> // {
> // const Elem * neighbor = inner_it->first.first;
> // if (neighbor->processor_id() != _mesh.processor_id())
> // continue;
> // ElementMap::const_iterator utl_it =
> // _upper_to_lower.find(neighbor);
> // libmesh_assert(utl_it != _upper_to_lower.end());
> // }
> // #endif
> }
> }
>
> void AugmentSparsityNonlocal::operator()
> (const MeshBase::const_element_iterator & range_begin,
> const MeshBase::const_element_iterator & range_end,
> processor_id_type p,
> map_type & coupled_elements)
> {
> libmesh_assert(this->_initialized);
>
> const CouplingMatrix * const null_mat = nullptr;
>
> for (const auto & elem : as_range(range_begin, range_end))
> {
> if (elem->processor_id() != p)
> coupled_elements.insert (std::make_pair(elem, null_mat));
>
> for (auto side : elem->side_index_range())
> if (elem->neighbor_ptr(side) == nullptr)
> {
> ElementSideMap::const_iterator ltu_it =
> _lower_to_upper.find(std::make_pair(elem, side));
> if (ltu_it != _lower_to_upper.end())
> {
> const Elem * neighbor = ltu_it->second;
> if (neighbor->processor_id() != p)
> coupled_elements.insert (std::make_pair(neighbor,
> null_mat));
> }
> }
>
> ElementMap::const_iterator utl_it =
> _upper_to_lower.find(elem);
> if (utl_it != _upper_to_lower.end())
> {
> const Elem * neighbor = utl_it->second;
> if (neighbor->processor_id() != p)
> coupled_elements.insert (std::make_pair(neighbor, null_mat));
> }
>
> }
>
>
> /*
> Nonlocal augment
> */
> // const CouplingMatrix * const null_mat = nullptr;
> libMesh::Patch::PMF patchtype = &Patch::add_face_neighbors;
> // #ifndef this->_target_patch_size
> // const unsigned int _target_patch_size=4;
> // #endif
> /* build element patches */
> for (const auto & elem : as_range(range_begin, range_end))
> {
> libMesh::Patch patch(_mesh.processor_id());
> patch.build_around_element(elem, _target_patch_size, patchtype);
> std::vector<const Elem *> patchvec;
> patchvec.reserve(patch.size());
> Patch::const_iterator patch_it = patch.begin();
> const Patch::const_iterator patch_end = patch.end();
> for (; patch_it != patch_end; ++patch_it)
> {
> const Elem * elem2 = *patch_it;
> coupled_elements.insert (std::make_pair(elem2, null_mat));
> // patchvec.push_back(elem2);
> }
> }
> }
>
>
>
> // MatSetOption(this->get_matrix("NonlocalStiffness"),
> MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);
> // DoFRenumbering::Cuthill_McKee (dof_handler);
> // hanging_node_constraints.clear();
> //
>
> DoFTools::make_hanging_node_constraints(dof_handler,hanging_node_constraints);
>
> // hanging_node_constraints.close();
>
> // DynamicSparsityPattern dsp(dof_handler.n_dofs(),
> dof_handler.n_dofs());
> // DoFTools::make_sparsity_pattern(dof_handler, dsp);
> // hanging_node_constraints.condense(dsp);
> // sparsity_pattern.copy_from(dsp);
>
> // stiffness_matrix.reinit(sparsity_pattern);
> // mass_matrix.reinit(sparsity_pattern);
>
>
>
>
>
>
>
>
>
>
_______________________________________________
Libmesh-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libmesh-users