Attention une mise à jour du service Gitlab va être effectuée le mardi 30 novembre entre 17h30 et 18h00. Cette mise à jour va générer une interruption du service dont nous ne maîtrisons pas complètement la durée mais qui ne devrait pas excéder quelques minutes. Cette mise à jour intermédiaire en version 14.0.12 nous permettra de rapidement pouvoir mettre à votre disposition une version plus récente.

Commit 201deb06 authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

#882 - #9 FiniteElement/FiniteElement: do the now usual namespace clean-up.

parent 46f51bc7
......@@ -6879,14 +6879,14 @@
path = Private;
sourceTree = "<group>";
};
BE3221851B4686B100F27D6C /* Private */ = {
BE3221851B4686B100F27D6C /* Internal */ = {
isa = PBXGroup;
children = (
BE3221861B4686B100F27D6C /* Local2GlobalStorage.cpp */,
BE3221871B4686B100F27D6C /* Local2GlobalStorage.hpp */,
BE3221881B4686B100F27D6C /* Local2GlobalStorage.hxx */,
);
path = Private;
path = Internal;
sourceTree = "<group>";
};
BE3292791A44701F009F0BE2 /* Exceptions */ = {
......@@ -9147,7 +9147,7 @@
BE13459D19CC171E003ED11A /* LocalFEltSpace.cpp */,
BE13459E19CC171E003ED11A /* LocalFEltSpace.hpp */,
BE13459F19CC171E003ED11A /* LocalFEltSpace.hxx */,
BE3221851B4686B100F27D6C /* Private */,
BE3221851B4686B100F27D6C /* Internal */,
);
path = FiniteElement;
sourceTree = "<group>";
......@@ -31,6 +31,11 @@
/// At the moment it is not documented as these are third party functions barely adapted
/// I have very few knowledge of.
/// \namespace HappyHeart::Internal::FEltNS
/// \brief Namespace that enclose helper classes of FElt and LocalFEltSpace.
///@}
......
......@@ -39,14 +39,21 @@ namespace HappyHeart
class LocalFEltSpace;
namespace Private
namespace Internal
{
class Local2GlobalStorage;
namespace FEltNS
{
} // namespace Private
class Local2GlobalStorage;
} // namespace FEltNS
} // namespace Internal
// ============================
......@@ -54,6 +61,9 @@ namespace HappyHeart
//! \endcond IGNORE_BLOCK_IN_DOXYGEN
// ============================
/// \addtogroup FElt
///@{
/*!
* \brief Finite element class.
......@@ -82,7 +92,7 @@ namespace HappyHeart
friend class LocalFEltSpace;
//! Friendship to Local2GlobalStorage; which needs to access to reference element.
friend class Private::Local2GlobalStorage;
friend class Internal::FEltNS::Local2GlobalStorage;
private:
......@@ -148,6 +158,9 @@ namespace HappyHeart
};
///@} // \addtogroup
} // namespace HappyHeart
......
//! \file
//
//
// Local2GlobalStorage.cpp
// HappyHeart
//
// Created by Sebastien Gilles on 29/06/15.
// Copyright (c) 2015 Inria. All rights reserved.
//
#include "FiniteElement/FiniteElement/Internal/Local2GlobalStorage.hpp"
#ifndef NDEBUG
# include "Utilities/Containers/Vector.hpp"
#endif // NDEBUG
namespace HappyHeart
{
namespace Internal
{
namespace FEltNS
{
namespace // anonymous
{
#ifndef NDEBUG
void AssertNotCleared(bool cleared)
{
assert(!cleared && "Should not be called once Clear() has been called! Clear() is usually called at the "
"very end of Model::Initialize()");
}
#endif // NDEBUG
}
Local2GlobalStorage::Local2GlobalStorage(const FElt::vector_shared_ptr& felt_list,
MpiScale mpi_scale)
: felt_list_(felt_list)
{
assert(std::none_of(felt_list.cbegin(),
felt_list.cend(),
Utilities::IsNullptr<FElt::shared_ptr>));
const auto& numbering_subset = felt_list.back()->GetExtendedUnknown().GetNumberingSubset();
assert(std::all_of(felt_list.cbegin(),
felt_list.cend(),
[&numbering_subset](const auto& felt_ptr)
{
return felt_ptr->GetExtendedUnknown().GetNumberingSubset() == numbering_subset;
}) && "All finite elements here should belong to the same numbering subset!");
auto& local_2_global_array = GetNonCstLocal2Global();
auto& unknown_id_list = GetNonCstUnknownIdList();
for (const auto& felt_ptr : felt_list)
{
assert(!(!felt_ptr));
const auto& felt = *felt_ptr;
unknown_id_list.push_back(felt.GetExtendedUnknown().GetUnknown().GetUniqueId());
const auto& node_list = felt.GetNodeList();
assert(!node_list.empty());
assert(std::none_of(node_list.cbegin(), node_list.cend(),
Utilities::IsNullptr<Node::shared_ptr>));
const auto Ncomponent = node_list.back()->Ndof();
for (unsigned int i = 0u; i < Ncomponent; ++i)
{
for (const auto& node_ptr : node_list)
{
const auto& dof = node_ptr->GetDof(i);
switch(mpi_scale)
{
case MpiScale::program_wise:
local_2_global_array.push_back(static_cast<PetscInt>(dof.GetProgramWiseIndex(numbering_subset)));
break;
case MpiScale::processor_wise:
local_2_global_array.push_back(static_cast<PetscInt>(dof.GetProcessorWiseOrGhostIndex(numbering_subset)));
break;
}
}
}
}
#ifndef NDEBUG
{
auto copy = unknown_id_list;
Utilities::EliminateDuplicate(copy);
assert(copy.size() == unknown_id_list.size() && "All finite elements should have been related to a "
"different unknown!");
}
#endif // NDEBUG
}
const std::vector<PetscInt>& Local2GlobalStorage
::GetLocal2Global(const ExtendedUnknown::vector_const_shared_ptr& unknown_list) const
{
const auto& local_2_global_per_unknown_id_list = GetLocal2GlobalPerUnknownIdList();
const auto Nunknown = unknown_list.size();
const auto end = local_2_global_per_unknown_id_list.cend();
auto it = std::find_if(local_2_global_per_unknown_id_list.cbegin(),
end,
[&unknown_list, Nunknown](const auto& pair)
{
const auto& current_unknown_list = pair.first;
if (current_unknown_list.size() != Nunknown)
return false;
for (unsigned int i = 0u; i < Nunknown; ++i)
{
if (current_unknown_list[i] != unknown_list[i]->GetUnknown().GetUniqueId())
return false;
}
return true;
});
assert(it != end && "GetLocal2Global() can only reach values previously computed by ComputeLocal2Global(); "
"if the issue is related to processor-wise local2global it is likely the DoComputeLocal2GLobalProcessorWise "
"argument should be set to yes. It might also be that the list of unknown is not used by any "
"operator, in which case it has not been pre-computed.");
return it->second;
}
const std::vector<PetscInt>& Local2GlobalStorage::GetLocal2Global(const ExtendedUnknown& unknown) const
{
const auto& local_2_global_per_unknown_id_list = GetLocal2GlobalPerUnknownIdList();
const auto end = local_2_global_per_unknown_id_list.cend();
const auto unknown_id = unknown.GetUnknown().GetUniqueId();
auto it = std::find_if(local_2_global_per_unknown_id_list.cbegin(),
end,
[unknown_id](const auto& pair)
{
const auto& current_unknown_list = pair.first;
if (current_unknown_list.size() != 1ul)
{
return false;
}
return current_unknown_list.back() == unknown_id;
});
assert(it != end && "GetLocal2Global() can only reach values previously computed by ComputeLocal2Global(); "
"if the issue is related to processor-wise local2global it is likely the DoComputeLocal2GLobalProcessorWise "
"argument should be set to yes. It might also be that the list of unknown is not used by any "
"operator, in which case it has not been pre-computed.");
return it->second;
}
void Local2GlobalStorage::ComputeLocal2Global(const ExtendedUnknown::vector_const_shared_ptr& unknown_list) const
{
#ifndef NDEBUG
{
AssertNotCleared(cleared_);
// Check all unknowns in the list are present in the storage.
const auto& storage_unknown_list = GetUnknownIdList();
std::set<unsigned int> check;
for (const auto& unknown_ptr : unknown_list)
{
assert(!(!unknown_ptr));
const auto id = unknown_ptr->GetUnknown().GetUniqueId();
const auto end = storage_unknown_list.cend();
assert(std::find(storage_unknown_list.cbegin(),
end,
id) != end);
check.insert(id);
}
assert(check.size() == unknown_list.size() && "There should be no duplicate in unknown_list!");
}
#endif // NDEBUG
// Determine the vector of unknown ids.
std::vector<unsigned int> unknown_id_list(unknown_list.size());
std::transform(unknown_list.cbegin(), unknown_list.cend(),
unknown_id_list.begin(),
[](const auto& unknown_ptr)
{
return unknown_ptr->GetUnknown().GetUniqueId();
});
auto& local_2_global_per_unknown_id_list = GetNonCstLocal2GlobalPerUnknownIdList();
// First determine if the sequence is already stored. If so, do nothing.
{
auto end = local_2_global_per_unknown_id_list.cend();
auto it = std::find_if(local_2_global_per_unknown_id_list.cbegin(),
end,
[&unknown_id_list](const auto& pair)
{
return pair.first == unknown_id_list;
});
if (it != end)
return;
}
// If not, compute the local2global for this list of unknowns.
const auto& felt_list = GetFEltList();
const auto begin_felt_list = felt_list.cbegin();
const auto end_felt_list = felt_list.cend();
std::vector<PetscInt> local2global_array;
const auto& local2global = GetLocal2Global();
#ifndef NDEBUG
const auto end_local2global = local2global.cend();
#endif // NDEBUG
for (const auto& unknown_ptr : unknown_list)
{
const auto& current_unknown_id = unknown_ptr->GetUnknown().GetUniqueId();
bool found = false;
unsigned int current_dof_count = 0u;
// Find in the finite element list the finite element matching the current unknown.
// There should be one by construct; an assert checks this in debug mode.
for (auto it = begin_felt_list; !found && it != end_felt_list; ++it)
{
const auto& felt_ptr = *it;
assert(!(!felt_ptr));
const auto& felt = *felt_ptr;
const auto& ref_felt_elt = felt.GetRefFElt();
const auto Ndof = ref_felt_elt.Ndof();
const auto felt_unknown_id = felt.GetExtendedUnknown().GetUnknown().GetUniqueId();
if (current_unknown_id == felt_unknown_id)
{
found = true;
auto it_begin = local2global.cbegin() + current_dof_count;
auto it_end = it_begin + Ndof;
assert(it_end <= end_local2global);
std::copy(it_begin, it_end, std::back_inserter(local2global_array));
}
current_dof_count += Ndof;
}
assert(found && "unknown_list given in argument should encompass only unknowns kown in the LocalFEltSpace");
}
// Complete the storage with new local2global array.
local_2_global_per_unknown_id_list.push_back(std::make_pair(std::move(unknown_id_list),
std::move(local2global_array)));
}
void Local2GlobalStorage::Clear() noexcept
{
assert(!cleared_ && "Clear() should be called at most once!");
local_2_global_.clear();
unknown_id_list_.clear();
#ifndef NDEBUG
cleared_ = true;
#endif // NDEBUG
}
const std::vector<PetscInt>& Local2GlobalStorage::GetLocal2Global() const noexcept
{
#ifndef NDEBUG
AssertNotCleared(cleared_);
#endif // NDEBUG
return local_2_global_;
}
std::vector<PetscInt>& Local2GlobalStorage::GetNonCstLocal2Global() noexcept
{
#ifndef NDEBUG
AssertNotCleared(cleared_);
#endif // NDEBUG
return const_cast<std::vector<PetscInt>&>(GetLocal2Global());
}
const std::vector<unsigned int>& Local2GlobalStorage::GetUnknownIdList() const noexcept
{
#ifndef NDEBUG
AssertNotCleared(cleared_);
#endif // NDEBUG
return unknown_id_list_;
}
} // namespace FEltNS
} // namespace Internal
} // namespace HappyHeart
//! \file
//
//
// Local2GlobalStorage.hpp
// HappyHeart
//
// Created by Sebastien Gilles on 29/06/15.
// Copyright (c) 2015 Inria. All rights reserved.
//
#ifndef HAPPY_HEART_x_FINITE_ELEMENT_x_FINITE_ELEMENT_x_PRIVATE_x_LOCAL2_GLOBAL_STORAGE_HPP_
# define HAPPY_HEART_x_FINITE_ELEMENT_x_FINITE_ELEMENT_x_PRIVATE_x_LOCAL2_GLOBAL_STORAGE_HPP_
# include <memory>
# include <vector>
# include "ThirdParty/IncludeWithoutWarning/Petsc/PetscSys.hpp"
# include "FiniteElement/Unknown/ExtendedUnknown.hpp"
# include "FiniteElement/FiniteElement/FElt.hpp"
namespace HappyHeart
{
// ============================
//! \cond IGNORE_BLOCK_IN_DOXYGEN
// Forward declarations.
// ============================
class LocalFEltSpace;
// ============================
// End of forward declarations.
//! \endcond IGNORE_BLOCK_IN_DOXYGEN
// ============================
namespace Internal
{
namespace FEltNS
{
/*!
* \brief Storage of all relevant local2global related to a \a LocalFEltSpace and a \a NumberingSubset.
*
* Within a given LocalFEltSpace, different operators might have different needs: one might need for instance
* the local2global related to only one unknown, and another the one related to several ones. The goal of
* current class is to store all relevant possibilities and give quick access to them.
*
* As Local2Global array makes sense only within a given numbering subset, there is one such object for each
* numbering subset.
*
* Similarly, Local2GlobalStorage might be used to store either processor-wise or program-wise local2global;
* in practice in LocalFEltSpace there are two different \a Local2GlobalStorage objects for either case.
*/
class Local2GlobalStorage
{
public:
//! Alias to self.
using self = Local2GlobalStorage;
//! Alias to unique pointer.
using unique_ptr = std::unique_ptr<self>;
//! Alias to vector of unique pointers.
using vector_unique_ptr = std::vector<unique_ptr> ;
//! Friendship to the class able to call ComputeLocal2Global().
friend class HappyHeart::LocalFEltSpace;
public:
/// \name Special members.
///@{
/*!
* \brief Constructor.
*
* Create here the list for the full numbering subset; partial lists are created on demand by a call
* to CreatePartialLocal2Global().
*
* \param[in] felt_list One or several finite element(s) considered by an operator, for which local2global
* must be reachable. They must share the same numbering subset (local2global would be meaningless for
* more than 1).
* \param[in] mpi_scale Whether we consider program-wise or processor-wise indexes.
*/
explicit Local2GlobalStorage(const FElt::vector_shared_ptr& felt_list,
MpiScale mpi_scale);
//! Destructor.
~Local2GlobalStorage() = default;
//! Copy constructor.
Local2GlobalStorage(const Local2GlobalStorage&) = delete;
//! Move constructor.
Local2GlobalStorage(Local2GlobalStorage&&) = delete;
//! Copy affectation.
Local2GlobalStorage& operator=(const Local2GlobalStorage&) = delete;
//! Move affectation.
Local2GlobalStorage& operator=(Local2GlobalStorage&&) = delete;
///@}
/*!
* \class doxygen_hide_local_2_global_storage_array
*
* It is assumed here it has already been computed with ComputeLocal2Global().
*
* \return Local -> global array.
*/
/*!
* \brief Get the local2global related to a list of unknowns, where local index is the position within the
* vector and global the value stored.
*
* \copydoc doxygen_hide_local_2_global_storage_array
*
* \param[in] unknown_list List of unknwowns for which local2global is required.
*
*/
const std::vector<PetscInt>& GetLocal2Global(const ExtendedUnknown::vector_const_shared_ptr& unknown_list) const;
/*!
* \brief Get the local2global related to a single unknown, where local index is the position within the
* vector and global the value stored.
*
* \copydoc doxygen_hide_local_2_global_storage_array
*
* \param[in] unknown Unknown for which local2global is required.
*/
const std::vector<PetscInt>& GetLocal2Global(const ExtendedUnknown& unknown) const;
/*!
* \brief Clear \a local_2_global_ and \a unknown_id_list_.
*
* This one is only required to build the others, which are required by operators. One each operator
* has built what it needs, there is no need to keep the first one, which might vbe quite heavy on memory.
*
*/
void Clear() noexcept;
private:
/*!
* \brief Compute Local2GLobal for a subset of the unknowns.