Skip to content

Commit 6f3c392

Browse files
authored
Merge pull request #163 from timetravellers/feature-clone-field
implement FieldData::clone()
2 parents 9c3069b + 86b4cdd commit 6f3c392

15 files changed

+321
-18
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/apfArrayData.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ class ArrayDataOf : public FieldDataOf<T>
7979
T* getDataArray() {
8080
return this->dataArray;
8181
}
82+
virtual FieldData* clone() {
83+
//FieldData* newData = new TagDataOf<double>();
84+
FieldData* newData = new ArrayDataOf<T>();
85+
newData->init(this->field);
86+
copyFieldData(static_cast<FieldDataOf<T>*>(newData),
87+
static_cast<FieldDataOf<T>*>(this->field->getData()));
88+
return newData;
89+
}
8290

8391
private:
8492
/* data variables go here */

apf/apfConvert.cc

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "apfNumbering.h"
88
#include <map>
99
#include <pcu_util.h>
10+
#include <iostream>
1011

1112
namespace apf {
1213

@@ -31,6 +32,9 @@ class Converter
3132
convertFields();
3233
convertNumberings();
3334
convertGlobalNumberings();
35+
// this must be called after anything that might create tags e.g. fields
36+
// or numberings to avoid problems with tag duplication
37+
convertTags();
3438
outMesh->acceptChanges();
3539
}
3640
ModelEntity* getNewModelFromOld(ModelEntity* oldC)
@@ -210,6 +214,48 @@ class Converter
210214
}
211215
}
212216
}
217+
void convertTag(Mesh* inMesh, MeshTag* in, Mesh* outMesh, MeshTag* out)
218+
{
219+
for (int d = 0; d <= 3; ++d) {
220+
int tagType = inMesh->getTagType(in);
221+
int tagSize = inMesh->getTagSize(in);
222+
PCU_DEBUG_ASSERT(tagType == outMesh->getTagType(out));
223+
PCU_DEBUG_ASSERT(tagSize == outMesh->getTagSize(out));
224+
MeshIterator* it = inMesh->begin(d);
225+
MeshEntity* e;
226+
while ((e = inMesh->iterate(it))) {
227+
if(inMesh->hasTag(e, in)) {
228+
// these initializations cannot go into the cases due to compiler
229+
// warnings on gcc 7.3.0
230+
double* dblData;
231+
int* intData;
232+
long* lngData;
233+
switch (tagType) {
234+
case apf::Mesh::TagType::DOUBLE:
235+
dblData = new double[tagSize];
236+
inMesh->getDoubleTag(e, in, dblData);
237+
outMesh->setDoubleTag(newFromOld[e], out, dblData);
238+
break;
239+
case apf::Mesh::TagType::INT:
240+
intData = new int[tagSize];
241+
inMesh->getIntTag(e, in, intData);
242+
outMesh->setIntTag(newFromOld[e], out, intData);
243+
break;
244+
case apf::Mesh::TagType::LONG:
245+
lngData = new long[tagSize];
246+
inMesh->getLongTag(e, in, lngData);
247+
outMesh->setLongTag(newFromOld[e], out, lngData);
248+
break;
249+
default:
250+
std::cerr << "Tried to convert unknown tag type\n";
251+
abort();
252+
break;
253+
}
254+
}
255+
}
256+
inMesh->end(it);
257+
}
258+
}
213259
void convertFields()
214260
{
215261
for (int i = 0; i < inMesh->countFields(); ++i) {
@@ -222,20 +268,76 @@ class Converter
222268
{
223269
for (int i = 0; i < inMesh->countNumberings(); ++i) {
224270
Numbering* in = inMesh->getNumbering(i);
225-
Numbering* out = createNumbering(outMesh,
226-
getName(in), getShape(in), countComponents(in));
271+
Numbering* out;
272+
if (getField(in)) {
273+
// here we assume that the fields have already been copied into the
274+
// mesh
275+
Field* outField = outMesh->findField(getName(getField(in)));
276+
PCU_DEBUG_ASSERT(outField);
277+
out = createNumbering(outField);
278+
}
279+
else {
280+
out = createNumbering(outMesh, getName(in), getShape(in),
281+
countComponents(in));
282+
}
227283
convertNumbering(in, out);
228284
}
229285
}
230286
void convertGlobalNumberings()
231287
{
232288
for (int i = 0; i < inMesh->countGlobalNumberings(); ++i) {
233289
GlobalNumbering* in = inMesh->getGlobalNumbering(i);
234-
GlobalNumbering* out = createGlobalNumbering(outMesh,
235-
getName(in), getShape(in), countComponents(in));
290+
GlobalNumbering* out;
291+
if (getField(in)) {
292+
// here we assume that the fields have already been copied into the
293+
// mesh
294+
Field* outField = outMesh->findField(getName(getField(in)));
295+
PCU_DEBUG_ASSERT(outField);
296+
out = createGlobalNumbering(outField);
297+
}
298+
else {
299+
out = createGlobalNumbering(outMesh, getName(in), getShape(in),
300+
countComponents(in));
301+
}
236302
convertGlobalNumbering(in, out);
237303
}
238304
}
305+
void convertTags()
306+
{
307+
DynamicArray<MeshTag*> tags;
308+
inMesh->getTags(tags);
309+
for (std::size_t i = 0; i < tags.getSize(); ++i) {
310+
apf::MeshTag* in = tags[i];
311+
PCU_DEBUG_ASSERT(in);
312+
// create a new tag on the outMesh
313+
int tagType = inMesh->getTagType(in);
314+
int tagSize = inMesh->getTagSize(in);
315+
const char* tagName = inMesh->getTagName(in);
316+
PCU_DEBUG_ASSERT(tagName);
317+
// need to make sure that the tag wasn't already created by a field or
318+
// numbering
319+
if (!outMesh->findTag(tagName)) {
320+
apf::MeshTag* out = NULL;
321+
switch (tagType) {
322+
case apf::Mesh::TagType::DOUBLE:
323+
out = outMesh->createDoubleTag(tagName, tagSize);
324+
break;
325+
case apf::Mesh::TagType::INT:
326+
out = outMesh->createIntTag(tagName, tagSize);
327+
break;
328+
case apf::Mesh::TagType::LONG:
329+
out = outMesh->createLongTag(tagName, tagSize);
330+
break;
331+
default:
332+
std::cerr << "Tried to convert unknown tag type\n";
333+
abort();
334+
}
335+
PCU_DEBUG_ASSERT(out);
336+
// copy the tag on the inMesh to the outMesh
337+
convertTag(inMesh, in, outMesh, out);
338+
}
339+
}
340+
}
239341
void convertQuadratic()
240342
{
241343
if (inMesh->getShape() != getLagrange(2) && inMesh->getShape() != getSerendipity())

apf/apfCoordData.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111

1212
namespace apf {
1313

14+
FieldData* CoordData::clone() {
15+
FieldData* newData = new CoordData();
16+
newData->init(field);
17+
copyFieldData(static_cast<FieldDataOf<double>*>(newData),
18+
static_cast<FieldDataOf<double>*>(field->getData()));
19+
return newData;
20+
21+
}
1422
void CoordData::init(FieldBase* f)
1523
{
1624
FieldData::field = f;

apf/apfCoordData.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class CoordData : public FieldDataOf<double>
3333
virtual void get(MeshEntity* e, double* data);
3434
virtual void set(MeshEntity* e, double const* data);
3535
virtual bool isFrozen() { return false; }
36+
virtual FieldData* clone();
3637
private:
3738
Mesh* mesh;
3839
FieldShape* shape;

apf/apfFieldData.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ FieldData::~FieldData()
1010
{
1111
}
1212

13-
FieldData* FieldData::clone()
14-
{
15-
abort();
16-
}
17-
1813
void FieldData::rename(const char*)
1914
{
2015
abort();

apf/apfFieldData.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class FieldData
2222
virtual bool hasEntity(MeshEntity* e) = 0;
2323
virtual void removeEntity(MeshEntity* e) = 0;
2424
virtual bool isFrozen() = 0;
25-
virtual FieldData* clone();
25+
virtual FieldData* clone() = 0;
2626
virtual void rename(const char* newName);
2727
FieldBase* getField() {return field;}
2828
protected:
@@ -55,6 +55,7 @@ class FieldDataOf : public FieldData
5555
void setNodeComponents(MeshEntity* e, int node, T const* components);
5656
void getNodeComponents(MeshEntity* e, int node, T* components);
5757
int getElementData(MeshEntity* entity, NewArray<T>& data);
58+
virtual FieldData* clone()=0;
5859
};
5960

6061
} //namespace apf

apf/apfNumbering.cc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,14 @@ GlobalNumbering* createGlobalNumbering(
461461
return n;
462462
}
463463

464+
GlobalNumbering* createGlobalNumbering(Field* f)
465+
{
466+
GlobalNumbering* n = new GlobalNumbering();
467+
n->init(f);
468+
f->getMesh()->addGlobalNumbering(n);
469+
return n;
470+
}
471+
464472
FieldShape* getShape(GlobalNumbering* n)
465473
{
466474
return n->getShape();
@@ -601,5 +609,5 @@ void getNodes(GlobalNumbering* n, DynamicArray<Node>& nodes)
601609
getFieldNodes(n,nodes);
602610
}
603611

612+
Field* getField(GlobalNumbering* n) { return n->getField(); }
604613
}
605-

apf/apfNumbering.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ GlobalNumbering* createGlobalNumbering(
159159
const char* name,
160160
FieldShape* shape,
161161
int components=1);
162+
163+
/** \brief Create a Numbering of degrees of freedom of a Field.
164+
*/
165+
GlobalNumbering* createGlobalNumbering(Field* f);
166+
162167
FieldShape* getShape(GlobalNumbering* n);
163168
const char* getName(GlobalNumbering* n);
164169
/** \brief get the mesh associated with a global numbering */
@@ -176,6 +181,9 @@ long getNumber(GlobalNumbering* n, MeshEntity* e, int node, int component=0);
176181
/** \brief get an element's global node numbers */
177182
int getElementNumbers(GlobalNumbering* n, MeshEntity* e,
178183
NewArray<long>& numbers);
184+
/** \brief get the field being numbered
185+
*/
186+
Field* getField(GlobalNumbering* n);
179187

180188
/** \brief converts a local numbering into a global numbering.
181189
\param destroy Should the input Numbering* be destroyed?

apf/apfUserData.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,13 @@ bool UserData::isFrozen()
4242
return false;
4343
}
4444

45+
FieldData* UserData::clone()
46+
{
47+
FieldData* newData = new UserData(function);
48+
newData->init(field);
49+
copyFieldData(static_cast<FieldDataOf<double>*>(newData),
50+
static_cast<FieldDataOf<double>*>(field->getData()));
51+
return newData;
52+
}
53+
4554
}

apf/apfUserData.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,15 @@ struct UserData : public FieldDataOf<double>
2121
void get(MeshEntity* e, double* data);
2222
void set(MeshEntity* e, double const* data);
2323
bool isFrozen();
24+
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:
2430
Function* function;
2531
};
2632

2733
}
2834

2935
#endif
30-
31-

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ util_exe_func(describe describe.cc)
2020
test_exe_func(quality quality.cc)
2121
test_exe_func(writeVtxPtn writeVtxPtn.cc)
2222
test_exe_func(verify_2nd_order_shapes verify_2nd_order_shapes.cc)
23+
test_exe_func(verify_convert verify_convert.cc)
2324

2425
# Geometric model utilities
2526
if(ENABLE_SIMMETRIX)

test/testing.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ mpi_test(integrate 1 ./integrate)
3333
mpi_test(qr_test 1 ./qr)
3434
mpi_test(base64 1 ./base64)
3535
mpi_test(tensor_test 1 ./tensor)
36+
mpi_test(verify_convert 1 ./verify_convert)
3637

3738
if(ENABLE_SIMMETRIX)
3839
mpi_test(in_closure_of 1

0 commit comments

Comments
 (0)