Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of support for complex fields #234

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apf/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ set(SOURCES
apfVectorElement.cc
apfVectorField.cc
apfPackedField.cc
apfComplexField.cc
apfNumbering.cc
apfMixedNumbering.cc
apfAdjReorder.cc
Expand All @@ -47,6 +48,7 @@ set(SOURCES
apfSimplexAngleCalcs.cc
apfFile.cc
apfMIS.cc
apfZero.cc
)

# Package headers
Expand All @@ -73,6 +75,7 @@ set(HEADERS
apfField.h
apfFieldData.h
apfNumberingClass.h
apfComplex.h
wrtobin marked this conversation as resolved.
Show resolved Hide resolved
)

# Add the apf library
Expand Down
45 changes: 40 additions & 5 deletions apf/apf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "apfMatrixField.h"
#include "apfMatrixElement.h"
#include "apfPackedField.h"
#include "apfComplexField.h"
#include "apfIntegrate.h"
#include "apfArrayData.h"
#include "apfTagData.h"
Expand Down Expand Up @@ -74,7 +75,7 @@ Field* makeField(
else if (valueType == PACKED)
f = new PackedField(components);
else
fail("invalid valueType in field construction\n");
fail("invalid valueType in double field construction\n");
f->init(name,m,shape,data);
m->addField(f);
return f;
Expand Down Expand Up @@ -126,8 +127,12 @@ Field* createPackedField(Mesh* m, const char* name, int components,

Field* cloneField(Field* f, Mesh* onto)
{
return makeField(onto, f->getName(), f->getValueType(), f->countComponents(),
f->getShape(), f->getData()->clone());
return makeField(onto,
f->getName(),
f->getValueType(),
f->countComponents(),
f->getShape(),
f->getData()->clone());
}

Mesh* getMesh(Field* f)
Expand Down Expand Up @@ -160,13 +165,15 @@ void destroyField(Field* f)

void setScalar(Field* f, MeshEntity* e, int node, double value)
{
PCU_DEBUG_ASSERT(f->getValueType() == SCALAR);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are now allowing c++11 in CORE can this be done with a static assert?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Core has been C++11 for a while IIRC. I've been using auto and range-based for's for a while no one has complained so far.

This assert has to be runtime though.

ScalarField* field = static_cast<ScalarField*>(f);
double tmp[1] = {value};
field->setNodeValue(e,node,tmp);
}

double getScalar(Field* f, MeshEntity* e, int node)
{
PCU_DEBUG_ASSERT(f->getValueType() == SCALAR);
ScalarField* field = static_cast<ScalarField*>(f);
double value[1];
field->getNodeValue(e,node,value);
Expand All @@ -175,13 +182,15 @@ double getScalar(Field* f, MeshEntity* e, int node)

void setVector(Field* f, MeshEntity* e, int node, Vector3 const& value)
{
PCU_DEBUG_ASSERT(f->getValueType() == VECTOR);
VectorField* field = static_cast<VectorField*>(f);
Vector3 tmp[1] = {value};
field->setNodeValue(e,node,tmp);
}

void getVector(Field* f, MeshEntity* e, int node, Vector3& value)
{
PCU_DEBUG_ASSERT(f->getValueType() == VECTOR);
VectorField* field = static_cast<VectorField*>(f);
Vector3 tmp[1];
field->getNodeValue(e,node,tmp);
Expand All @@ -190,13 +199,15 @@ void getVector(Field* f, MeshEntity* e, int node, Vector3& value)

void setMatrix(Field* f, MeshEntity* e, int node, Matrix3x3 const& value)
{
PCU_DEBUG_ASSERT(f->getValueType() == MATRIX);
MatrixField* field = static_cast<MatrixField*>(f);
Matrix3x3 tmp[1] = {value};
field->setNodeValue(e,node,tmp);
}

void getMatrix(Field* f, MeshEntity* e, int node, Matrix3x3& value)
{
PCU_DEBUG_ASSERT(f->getValueType() == MATRIX);
MatrixField* field = static_cast<MatrixField*>(f);
Matrix3x3 tmp[1];
field->getNodeValue(e,node,tmp);
Expand All @@ -205,11 +216,15 @@ void getMatrix(Field* f, MeshEntity* e, int node, Matrix3x3& value)

void setComponents(Field* f, MeshEntity* e, int node, double const* components)
{
PCU_DEBUG_ASSERT(f->getScalarType() == Mesh::DOUBLE &&
(f->getValueType() == SCALAR || f->getValueType() == PACKED));
f->getData()->setNodeComponents(e,node,components);
}

void getComponents(Field* f, MeshEntity* e, int node, double* components)
{
PCU_DEBUG_ASSERT(f->getScalarType() == Mesh::DOUBLE &&
(f->getValueType() == SCALAR || f->getValueType() == PACKED));
f->getData()->getNodeComponents(e,node,components);
}

Expand Down Expand Up @@ -240,49 +255,57 @@ MeshEntity* getMeshEntity(Element* e)

double getScalar(Element* e, Vector3 const& param)
{
PCU_DEBUG_ASSERT(dynamic_cast<ScalarElement*>(e) != NULL);
ScalarElement* element = static_cast<ScalarElement*>(e);
return element->getValue(param);
}

void getGrad(Element* e, Vector3 const& param, Vector3& g)
{
PCU_DEBUG_ASSERT(dynamic_cast<ScalarElement*>(e) != NULL);
ScalarElement* element = static_cast<ScalarElement*>(e);
element->grad(param,g);
}

void getVector(Element* e, Vector3 const& param, Vector3& value)
{
PCU_DEBUG_ASSERT(dynamic_cast<VectorElement*>(e) != NULL);
VectorElement* element = static_cast<VectorElement*>(e);
value = element->getValue(param);
}

double getDiv(Element* e, Vector3 const& param)
{
PCU_DEBUG_ASSERT(dynamic_cast<VectorElement*>(e) != NULL);
VectorElement* element = static_cast<VectorElement*>(e);
return element->div(param);
}

void getCurl(Element* e, Vector3 const& param, Vector3& c)
{
PCU_DEBUG_ASSERT(dynamic_cast<VectorElement*>(e) != NULL);
VectorElement* element = static_cast<VectorElement*>(e);
return element->curl(param,c);
}

void getVectorGrad(Element* e, Vector3 const& param, Matrix3x3& deriv)
{
PCU_DEBUG_ASSERT(dynamic_cast<VectorElement*>(e) != NULL);
VectorElement* element = static_cast<VectorElement*>(e);
return element->grad(param,deriv);
}

void getMatrix(Element* e, Vector3 const& param, Matrix3x3& value)
{
PCU_DEBUG_ASSERT(dynamic_cast<MatrixElement*>(e) != NULL);
MatrixElement* element = static_cast<MatrixElement*>(e);
value = element->getValue(param);
}


void getMatrixGrad(Element* e, Vector3 const& param, Vector<27>& deriv)
{
PCU_DEBUG_ASSERT(dynamic_cast<MatrixElement*>(e) != NULL);
MatrixElement* element = static_cast<MatrixElement*>(e);
return element->grad(param,deriv);
}
Expand Down Expand Up @@ -371,27 +394,39 @@ double computeCosAngle(Mesh* m, MeshEntity* pe, MeshEntity* e1, MeshEntity* e2,

int countNodes(Element* e)
{
return e->getShape()->countNodes();
return countNodes(static_cast<ElementBase*>(e));
}

void getScalarNodes(Element* e, NewArray<double>& values)
{
PCU_DEBUG_ASSERT(dynamic_cast<ElementOf<double>*>(e) != NULL);
ElementOf<double>* element = static_cast<ElementOf<double>*>(e);
element->getValues(values);
}

void getVectorNodes(Element* e, NewArray<Vector3>& values)
{
PCU_DEBUG_ASSERT(dynamic_cast<ElementOf<Vector3>*>(e) != NULL);
ElementOf<Vector3>* element = static_cast<ElementOf<Vector3>*>(e);
element->getValues(values);
}

void getMatrixNodes(Element* e, NewArray<Matrix3x3>& values)
{
PCU_DEBUG_ASSERT(dynamic_cast<ElementOf<Matrix3x3>*>(e) != NULL);
ElementOf<Matrix3x3>* element = static_cast<ElementOf<Matrix3x3>*>(e);
element->getValues(values);
}

void getPackedNodes(Element* e, NewArray<double>& values)
{
FieldBase* f = e->getFieldBase();
int cmps = f->countComponents();
PCU_DEBUG_ASSERT(dynamic_cast<ElementOf<double>*>(e) != NULL);
ElementOf<double>* element = static_cast<ElementOf<double>*>(e);
element->getValues(values,cmps);
}

void getShapeValues(Element* e, Vector3 const& local,
NewArray<double>& values)
{
Expand Down Expand Up @@ -473,7 +508,7 @@ void unfreeze(Field* f)

bool isFrozen(Field* f)
{
return f->getData()->isFrozen();
return isFrozen(static_cast<FieldBase*>(f));
}

Function::~Function()
Expand Down
17 changes: 16 additions & 1 deletion apf/apf.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ template <class T> class ReductionOp;
template <class T> class ReductionSum;

/** \brief Base class for applying operations to make a Field consistent
* in parallel
* in parallel
* \details This function gets applied pairwise to the Field values
* from every partition, resulting in a single unique value. No guarantees
* are made about the order in which this function is applied to the
Expand Down Expand Up @@ -569,6 +569,10 @@ void getVectorNodes(Element* e, NewArray<Vector3>& values);
*/
void getMatrixNodes(Element* e, NewArray<Matrix3x3>& values);

/** \brief Returns the element nodal values for a packed field
*/
void getPackedNodes(Element* e, NewArray<double>& values);

/** \brief Returns the shape function values at a point
*/
void getShapeValues(Element* e, Vector3 const& local,
Expand Down Expand Up @@ -717,9 +721,20 @@ bool isFrozen(Field* f);
\details This function is only defined for fields
which are using array storage, for which apf::isFrozen
returns true.
\note If the underlying field data type is NOT double,
this will cause an assert fail in all compile modes.
*/
double* getArrayData(Field* f);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a mechanism for depreciation? If so, this should probably be depreciated and replaced with getDoubleArrayData to have a consistent API.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since C++14 we have [[deprecated]], though this codebase is explicitly only up to C++11 IIRC and we haven't put in a deprecation mechanism as far as I know.

C++14 was basically just a small step from 11 so moving core to that should be possible, but is a different issue.

For the time being I will introduce a more consistent API function and not in the doxygen this is deprecated (see apfNumbering.h near the bottom for the only other place this has been done I think).


/** \brief Return the contiguous array storing this field.
\details This function is only defined for fields
which are using array storage, for which apf::isFrozen
returns true.
\note If the underlying field data type is NOT int,
this will cause an assert fail in all compile modes.
*/
int* getIntArrayData(Field* f);

/** \brief Initialize all nodal values with all-zero components */
void zeroField(Field* f);

Expand Down
37 changes: 32 additions & 5 deletions apf/apfArrayData.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "apfArrayData.h"
#include "apfComplex.h"
#include "apfNumbering.h"
#include "apfTagData.h"
#include <pcu_util.h>
#include <type_traits>

namespace apf {

Expand Down Expand Up @@ -125,19 +128,43 @@ void unfreezeFieldData(FieldBase* field) {
}

/* instantiate here */
template void freezeFieldData<double_complex>(FieldBase* field);
template void freezeFieldData<int>(FieldBase* field);
template void freezeFieldData<double>(FieldBase* field);
template void unfreezeFieldData<double_complex>(FieldBase * field);
template void unfreezeFieldData<int>(FieldBase* field);
template void unfreezeFieldData<double>(FieldBase* field);

double* getArrayData(Field* f) {
if (!isFrozen(f)) {
template <typename T>
T* getArrayDataT(FieldBase* f)
{
int scalar = f->getScalarType();
// having to assert this is terrible and if we add more field types
// unsustainable and bad practice, but the current other option is
// changing the API and being more explicit about type storage
// since Field assumes it has Scalars of type double
PCU_ALWAYS_ASSERT(
(scalar == Mesh::DOUBLE && std::is_same<T,double>::value) ||
(scalar == Mesh::INT && std::is_same<T,int>::value) ||
(scalar == Mesh::LONG && std::is_same<T,long>::value) ||
(scalar == Mesh::COMPLEX && std::is_same<T,double_complex>::value)
);
if(!isFrozen(f))
return 0;
} else {
FieldDataOf<double>* p = f->getData();
ArrayDataOf<double>* a = static_cast<ArrayDataOf<double>* > (p);
else
{
FieldDataOf<T>* p = reinterpret_cast<FieldDataOf<T>*>(f->getData());
ArrayDataOf<T>* a = static_cast<ArrayDataOf<T>*>(p);
return a->getDataArray();
}
}

template double_complex* getArrayDataT(FieldBase* field);
template int* getArrayDataT(FieldBase* field);
template double* getArrayDataT(FieldBase* field);

double * getArrayData(Field * f) { return getArrayDataT<double>(f); }
int * getIntArrayData(Field * f) { return getArrayDataT<int>(f); }
double_complex * getComplexArrayData(Field * f) { return getArrayDataT<double_complex>(f); }

}
67 changes: 67 additions & 0 deletions apf/apfComplex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#ifndef APFCOMPLEX_H_
#define APFCOMPLEX_H_

#ifdef C_COMPLEX
#include <complex.h>
#endif

#define CXX_COMPLEX 1
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, need to add this as a CMake option rather that just hard defining it to be CXX_COMPLEX for now.

#ifdef CXX_COMPLEX
#include <complex>
using double_complex = std::complex<double>;
#endif

namespace apf
{

// forward decls for the interface
class ComplexElement;
class ComplexField;
class Mesh;
class FieldShape;
class MeshEntity;
class VectorElement;
typedef VectorElement MeshElement;
class Vector3;
template <class T>
class NewArray;

ComplexField* createComplexField(Mesh* m,
const char* name,
int valueType,
int components,
FieldShape* shape);

void freeze(ComplexField* f);
void unfreeze(ComplexField* f);
bool isFrozen(ComplexField* f);

/** \brief Return the contiguous array storing this field.
\details This function is only defined for fields
which are using array storage, for which apf::isFrozen
returns true.
\note If the underlying field data type is NOT double_complex,
this will cause an assert fail in all compile modes.
*/
double_complex* getComplexArrayData(ComplexField * f);
void zeroField(ComplexField* f);

void setComponents(ComplexField* f, MeshEntity* e, int node, double_complex const * components);
void getComponents(ComplexField* f, MeshEntity* e, int node, double_complex * components);

ComplexElement* createElement(ComplexField* f, MeshElement* e);
ComplexElement* createElement(ComplexField* f, MeshEntity* e);
void destroyElement(ComplexElement* e);

MeshElement* getMeshElement(ComplexElement* e);
MeshEntity* getMeshEntity(ComplexElement* e);

void getComponents(ComplexElement* e, Vector3 const& param, double_complex* components);
int countNodes(ComplexElement* e);
void getShapeValues(ComplexElement* e);
void getShapeGrads(ComplexElement* e);
void getPackedNodes(ComplexElement* e, NewArray<double_complex>& values);
wrtobin marked this conversation as resolved.
Show resolved Hide resolved

}

#endif
Loading