Skip to content

Commit 5852fd3

Browse files
committed
add function to update user field function
this is important if the apf::Function stores a field for computation. It allows the user to update the apf::Function to use the proper field.
1 parent a2084bf commit 5852fd3

File tree

4 files changed

+77
-29
lines changed

4 files changed

+77
-29
lines changed

apf/apf.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,13 @@ Field* createUserField(Mesh* m, const char* name, int valueType, FieldShape* s,
463463
return makeField(m, name, valueType, 0, s, new UserData(f));
464464
}
465465

466+
void updateUserField(Field* field, Function* newFunc)
467+
{
468+
UserData* ud = dynamic_cast<UserData*>(field->getData());
469+
// ud will be null if the data is not user data
470+
if (ud) ud->setFunction(newFunc);
471+
}
472+
466473
void copyData(Field* to, Field* from)
467474
{
468475
copyFieldData(from->getData(), to->getData());

apf/apf.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -668,14 +668,22 @@ struct Function
668668
virtual void eval(MeshEntity* e, double* result) = 0;
669669
};
670670

671-
/** \brief Create a Field from a user's analytic function.
672-
\details This field will use no memory, has values on all
673-
nodes, and calls the user Function for all value queries.
674-
Writing to this field does nothing.
675-
*/
671+
/* \brief Create a Field from a user's analytic function.
672+
* \details This field will use no memory, has values on all
673+
* nodes, and calls the user Function for all value queries.
674+
* Writing to this field does nothing.
675+
* \warning if you copy the mesh with apf::convert you may want to use
676+
* apf::updateUserField to update function that this field refers to. This is
677+
* extremely important if the analytic function you use references user fields.
678+
*/
676679
Field* createUserField(Mesh* m, const char* name, int valueType, FieldShape* s,
677680
Function* f);
678681

682+
/* \brief update the analytic function from a user field
683+
* \details this field updates the apf::Function which the UserField refers to
684+
*/
685+
void updateUserField(Field* field, Function* newFunc);
686+
679687
/** \brief Compute a nodal gradient field from a nodal input field
680688
\details given a nodal field, compute approximate nodal gradient
681689
values by giving each node a volume-weighted average of the

apf/apfUserData.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@ struct UserData : public FieldDataOf<double>
2222
void set(MeshEntity* e, double const* data);
2323
bool isFrozen();
2424
virtual FieldData* clone();
25+
// using const * const gives an error on gcc/7.3.0 because the return is an
26+
// r-value which cannot be modified anyways
27+
Function const* getFunction() const { return function; }
28+
void setFunction(Function* func) { function = func; }
29+
private:
2530
Function* function;
2631
};
2732

2833
}
2934

3035
#endif
31-
32-

test/verify_convert.cc

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,90 @@
11
/*
22
* this test verifies that the convert process properly clones the underlying
3-
* fields and numberings
3+
* fields
44
*/
5+
#include <PCU.h>
56
#include <apf.h>
7+
#include <apfConvert.h>
8+
#include <apfMDS.h>
9+
#include <apfMesh2.h>
610
#include <gmi_null.h>
7-
#include <PCU.h>
811
#include <pcu_util.h>
9-
#include <apfMesh2.h>
10-
#include <apfMDS.h>
11-
#include <apfConvert.h>
12-
13-
apf::Mesh2* createEmptyMesh() {
12+
#include <cassert>
13+
apf::Mesh2* createEmptyMesh()
14+
{
1415
gmi_model* mdl = gmi_load(".null");
1516
return apf::makeEmptyMdsMesh(mdl, 3, false);
1617
}
17-
apf::Mesh2* createMesh() {
18+
apf::Mesh2* createMesh()
19+
{
1820
apf::Mesh2* m = createEmptyMesh();
1921
apf::MeshEntity* verts[2];
20-
verts[0] = m->createVertex(NULL, apf::Vector3(0,0,0), apf::Vector3(0,0,0));
21-
verts[1] = m->createVertex(NULL, apf::Vector3(1,0,0), apf::Vector3(1,0,0));
22+
verts[0] =
23+
m->createVertex(NULL, apf::Vector3(0, 0, 0), apf::Vector3(0, 0, 0));
24+
verts[1] =
25+
m->createVertex(NULL, apf::Vector3(1, 0, 0), apf::Vector3(1, 0, 0));
2226
m->createEntity(apf::Mesh::Type::EDGE, NULL, verts);
2327
return m;
2428
}
29+
class twox : public apf::Function {
30+
private:
31+
apf::Field* x;
2532

26-
int main(int argc, char* argv[]) {
27-
MPI_Init(&argc,&argv);
33+
public:
34+
virtual void eval(apf::MeshEntity* e, double* result)
35+
{
36+
result[0] = 2 * apf::getScalar(x, e, 0);
37+
}
38+
twox(apf::Field* x) : x(x) {}
39+
};
40+
int main(int argc, char* argv[])
41+
{
42+
MPI_Init(&argc, &argv);
2843
PCU_Comm_Init();
2944
gmi_register_null();
3045
apf::Mesh* m1 = createMesh();
3146
apf::Mesh2* m2 = createEmptyMesh();
3247
// create field on m1
3348
apf::Field* f = apf::createLagrangeField(m1, "field1", apf::SCALAR, 1);
49+
apf::Function* func = new twox(f);
50+
apf::Field* uf =
51+
apf::createUserField(m1, "ufield1", apf::SCALAR, apf::getShape(f), func);
3452
// loop over all vertices in mesh and set values
3553
int count = 1;
3654
apf::MeshIterator* it = m1->begin(0);
37-
while(apf::MeshEntity * vert = m1->iterate(it)) {
55+
while (apf::MeshEntity* vert = m1->iterate(it)) {
3856
apf::setScalar(f, vert, 0, count++);
3957
}
4058
m1->end(it);
59+
// verify the user field works on mesh 1
60+
it = m1->begin(0);
61+
while (apf::MeshEntity* vert = m1->iterate(it)) {
62+
double val = apf::getScalar(f, vert, 0);
63+
double uval = apf::getScalar(uf, vert, 0);
64+
if (!(std::abs(uval - 2 * double(val)) < 1E-15)) return 1;
65+
}
66+
m1->end(it);
4167
// copy m1 to m2
42-
apf::convert(m1, m2);
43-
// read values from m2 and verify that they match values on m1
44-
// here we assume that the nodes are ordered in the same way for
45-
// both meshes
68+
apf::convert(m1, m2);
4669
apf::Field* f2 = m2->findField("field1");
70+
apf::Field* uf2 = m2->findField("ufield1");
71+
// update the user field to reference the field in mesh 2
72+
apf::updateUserField(uf2, new twox(f2));
4773
count = 1;
4874
it = m2->begin(0);
49-
while(apf::MeshEntity * vert = m2->iterate(it) ) {
75+
while (apf::MeshEntity* vert = m2->iterate(it)) {
5076
double val = apf::getScalar(f2, vert, 0);
51-
if(!(std::abs(val-count) < 1E-15))
52-
return 1;
77+
double uval = apf::getScalar(uf2, vert, 0);
78+
assert(std::abs(val - count) < 1E-15);
79+
assert(std::abs(uval - 2 * double(count)) < 1E-15);
80+
apf::setScalar(f2, vert, 0, 18.0);
81+
// make sure that the function updated properly
82+
uval = apf::getScalar(uf2, vert, 0);
83+
assert(std::abs(uval - 36.0) < 1E-15);
5384
++count;
5485
}
5586
m2->end(it);
56-
57-
87+
delete func;
5888
m1->destroyNative();
5989
m2->destroyNative();
6090
apf::destroyMesh(m1);

0 commit comments

Comments
 (0)