176 lines
5.5 KiB
C++
176 lines
5.5 KiB
C++
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
|
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
|
// reserved. See file COPYRIGHT for details.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability see http://mfem.org.
|
|
//
|
|
// MFEM is free software; you can redistribute it and/or modify it under the
|
|
// terms of the GNU Lesser General Public License (as published by the Free
|
|
// Software Foundation) version 2.1 dated February 1999.
|
|
|
|
#include "ceed.hpp"
|
|
|
|
#ifdef MFEM_USE_CEED
|
|
#include "../../general/device.hpp"
|
|
#include "../../fem/gridfunc.hpp"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#ifndef _WIN32
|
|
typedef struct stat struct_stat;
|
|
#else
|
|
#define stat(dir, buf) _stat(dir, buf)
|
|
#define S_ISDIR(mode) _S_IFDIR(mode)
|
|
typedef struct _stat struct_stat;
|
|
#endif
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
namespace internal
|
|
{
|
|
|
|
extern Ceed ceed;
|
|
|
|
std::string ceed_path;
|
|
|
|
}
|
|
|
|
void InitCeedCoeff(Coefficient* Q, CeedData* ptr)
|
|
{
|
|
if (ConstantCoefficient* coeff = dynamic_cast<ConstantCoefficient*>(Q))
|
|
{
|
|
CeedConstCoeff* ceedCoeff = new CeedConstCoeff{coeff->constant};
|
|
ptr->coeff_type = CeedCoeff::Const;
|
|
ptr->coeff = (void*)ceedCoeff;
|
|
}
|
|
else if (GridFunctionCoefficient* coeff =
|
|
dynamic_cast<GridFunctionCoefficient*>(Q))
|
|
{
|
|
CeedGridCoeff* ceedCoeff = new CeedGridCoeff;
|
|
ceedCoeff->coeff = coeff->GetGridFunction();
|
|
ptr->coeff_type = CeedCoeff::Grid;
|
|
ptr->coeff = (void*)ceedCoeff;
|
|
}
|
|
else
|
|
{
|
|
MFEM_ABORT("This type of Coefficient is not supported.");
|
|
}
|
|
}
|
|
|
|
void InitCeedTensorBasisAndRestriction(const mfem::FiniteElementSpace &fes,
|
|
const mfem::IntegrationRule &ir,
|
|
Ceed ceed, CeedBasis *basis,
|
|
CeedElemRestriction *restr)
|
|
{
|
|
mfem::Mesh *mesh = fes.GetMesh();
|
|
const mfem::FiniteElement *fe = fes.GetFE(0);
|
|
const int order = fes.GetOrder(0);
|
|
mfem::Array<int> dof_map;
|
|
switch (mesh->Dimension())
|
|
{
|
|
case 1:
|
|
{
|
|
const mfem::H1_SegmentElement *h1_fe =
|
|
dynamic_cast<const mfem::H1_SegmentElement *>(fe);
|
|
MFEM_VERIFY(h1_fe, "invalid FE");
|
|
h1_fe->GetDofMap().Copy(dof_map);
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
const mfem::H1_QuadrilateralElement *h1_fe =
|
|
dynamic_cast<const mfem::H1_QuadrilateralElement *>(fe);
|
|
MFEM_VERIFY(h1_fe, "invalid FE");
|
|
h1_fe->GetDofMap().Copy(dof_map);
|
|
break;
|
|
}
|
|
case 3:
|
|
{
|
|
const mfem::H1_HexahedronElement *h1_fe =
|
|
dynamic_cast<const mfem::H1_HexahedronElement *>(fe);
|
|
MFEM_VERIFY(h1_fe, "invalid FE");
|
|
h1_fe->GetDofMap().Copy(dof_map);
|
|
break;
|
|
}
|
|
}
|
|
const mfem::FiniteElement *fe1d =
|
|
fes.FEColl()->FiniteElementForGeometry(mfem::Geometry::SEGMENT);
|
|
mfem::DenseMatrix shape1d(fe1d->GetDof(), ir.GetNPoints());
|
|
mfem::DenseMatrix grad1d(fe1d->GetDof(), ir.GetNPoints());
|
|
mfem::Vector qref1d(ir.GetNPoints()), qweight1d(ir.GetNPoints());
|
|
mfem::Vector shape_i(shape1d.Height());
|
|
mfem::DenseMatrix grad_i(grad1d.Height(), 1);
|
|
const mfem::H1_SegmentElement *h1_fe1d =
|
|
dynamic_cast<const mfem::H1_SegmentElement *>(fe1d);
|
|
MFEM_VERIFY(h1_fe1d, "invalid FE");
|
|
const mfem::Array<int> &dof_map_1d = h1_fe1d->GetDofMap();
|
|
for (int i = 0; i < ir.GetNPoints(); i++)
|
|
{
|
|
const mfem::IntegrationPoint &ip = ir.IntPoint(i);
|
|
qref1d(i) = ip.x;
|
|
qweight1d(i) = ip.weight;
|
|
fe1d->CalcShape(ip, shape_i);
|
|
fe1d->CalcDShape(ip, grad_i);
|
|
for (int j = 0; j < shape1d.Height(); j++)
|
|
{
|
|
shape1d(j, i) = shape_i(dof_map_1d[j]);
|
|
grad1d(j, i) = grad_i(dof_map_1d[j], 0);
|
|
}
|
|
}
|
|
CeedBasisCreateTensorH1(ceed, mesh->Dimension(), fes.GetVDim(), order + 1,
|
|
ir.GetNPoints(), shape1d.GetData(),
|
|
grad1d.GetData(), qref1d.GetData(),
|
|
qweight1d.GetData(), basis);
|
|
|
|
const mfem::Table &el_dof = fes.GetElementToDofTable();
|
|
mfem::Array<int> tp_el_dof(el_dof.Size_of_connections());
|
|
for (int i = 0; i < mesh->GetNE(); i++)
|
|
{
|
|
const int el_offset = fe->GetDof() * i;
|
|
for (int j = 0; j < fe->GetDof(); j++)
|
|
{
|
|
tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset];
|
|
}
|
|
}
|
|
CeedInterlaceMode imode = CEED_NONINTERLACED;
|
|
if (fes.GetOrdering()==Ordering::byVDIM)
|
|
{
|
|
imode = CEED_INTERLACED;
|
|
}
|
|
CeedElemRestrictionCreate(ceed, imode, mesh->GetNE(), fe->GetDof(),
|
|
fes.GetNDofs(), fes.GetVDim(), CEED_MEM_HOST, CEED_COPY_VALUES,
|
|
tp_el_dof.GetData(), restr);
|
|
}
|
|
|
|
const std::string &GetCeedPath()
|
|
{
|
|
if (internal::ceed_path.empty())
|
|
{
|
|
const char *install_dir = MFEM_INSTALL_DIR "/include/mfem/fem/libceed";
|
|
const char *source_dir = MFEM_SOURCE_DIR "/fem/libceed";
|
|
struct_stat m_stat;
|
|
if (stat(install_dir, &m_stat) == 0 && S_ISDIR(m_stat.st_mode))
|
|
{
|
|
internal::ceed_path = install_dir;
|
|
}
|
|
else if (stat(source_dir, &m_stat) == 0 && S_ISDIR(m_stat.st_mode))
|
|
{
|
|
internal::ceed_path = source_dir;
|
|
}
|
|
else
|
|
{
|
|
MFEM_ABORT("Cannot find libCEED kernels in MFEM_INSTALL_DIR or "
|
|
"MFEM_SOURCE_DIR");
|
|
}
|
|
// Could be useful for debugging:
|
|
// mfem::out << "Using libCEED dir: " << internal::ceed_path << std::endl;
|
|
}
|
|
return internal::ceed_path;
|
|
}
|
|
|
|
} // namespace mfem
|
|
|
|
#endif // MFEM_USE_CEED
|