libMesh
composite_function_test.C
Go to the documentation of this file.
1 // libmesh includes
2 #include <libmesh/composite_function.h>
3 #include <libmesh/const_function.h>
4 #include <libmesh/dense_vector.h>
5 #include <libmesh/parsed_function.h>
6 #include <libmesh/zero_function.h>
7 #include <libmesh/analytic_function.h>
8 
9 #include "libmesh_cppunit.h"
10 
11 
12 using namespace libMesh;
13 
14 class CompositeFunctionTest : public CppUnit::TestCase
15 {
16 public:
17  void setUp() {}
18 
19  void tearDown() {}
20 
21  LIBMESH_CPPUNIT_TEST_SUITE(CompositeFunctionTest);
22 
23  CPPUNIT_TEST(testRemap);
24 #if LIBMESH_DIM > 2
25  CPPUNIT_TEST(testTimeDependence);
26 #endif
27 
28  CPPUNIT_TEST_SUITE_END();
29 
30 
31 private:
32  void testRemap()
33  {
34  LOG_UNIT_TEST;
35 
36  std::vector<std::vector<unsigned int>> index_sets(4);
37  index_sets[0].resize(2);
38  index_sets[0][0] = 3;
39  index_sets[0][1] = 4;
40  index_sets[1].resize(3);
41  index_sets[1][0] = 0;
42  index_sets[1][1] = 1;
43  index_sets[1][2] = 2;
44  index_sets[2].resize(3);
45  index_sets[2][0] = 0;
46  index_sets[2][1] = 2;
47  index_sets[2][2] = 4;
48  index_sets[3].resize(5);
49  index_sets[3][0] = 5;
50  index_sets[3][1] = 1;
51  index_sets[3][2] = 3;
52  index_sets[3][3] = 6;
53  index_sets[3][4] = 7;
54 
55  CompositeFunction<Real> composite_outer;
56 
57  {
58  CompositeFunction<Real> composite_inner;
59 
60  // Test that ConstFunction copy construction works.
61  ConstFunction<Real> cf_one(1);
62  ConstFunction<Real> cf_one_copy(cf_one);
63  composite_inner.attach_subfunction (cf_one_copy, index_sets[0]);
64 
65  // Test that ConstFunction move construction works.
66  ConstFunction<Real> cf_two(2);
67  ConstFunction<Real> cf_two_move(std::move(cf_two));
68  composite_inner.attach_subfunction (cf_two_move, index_sets[1]);
69 
70  composite_outer.attach_subfunction
71  (composite_inner, index_sets[3]);
72 
73  DenseVector<Real> test_one(5);
74 
75  composite_inner(Point(0), 0, test_one);
76 
77  LIBMESH_ASSERT_FP_EQUAL(2, test_one(0), 1.e-12);
78  LIBMESH_ASSERT_FP_EQUAL(2, test_one(1), 1.e-12);
79  LIBMESH_ASSERT_FP_EQUAL(2, test_one(2), 1.e-12);
80  LIBMESH_ASSERT_FP_EQUAL(1, test_one(3), 1.e-12);
81  LIBMESH_ASSERT_FP_EQUAL(1, test_one(4), 1.e-12);
82  }
83  // Test that ConstFunction copy- and move-assignment works.
84  ConstFunction<Real> cf_three(3);
85  ConstFunction<Real> cf_three_copy_assign(0);
86  ConstFunction<Real> cf_three_move_assign(0);
87  cf_three_copy_assign = cf_three;
88  cf_three_move_assign = std::move(cf_three_copy_assign);
89  composite_outer.attach_subfunction(cf_three_move_assign, index_sets[2]);
90 
91  // Test that move ctor works. Note that composite_outer should not
92  // be used for anything once it has been moved from!
93  CompositeFunction<Real> composite_outer_copy1(std::move(composite_outer));
94 
95  // Test that move assignment also works. The first copy should not be
96  // used again after being move assigned.
97  CompositeFunction<Real> composite_outer_copy2;
98  composite_outer_copy2 = std::move(composite_outer_copy1);
99 
100  DenseVector<Real> test_two(8);
101  composite_outer_copy2(Point(0), 0, test_two);
102 
103  LIBMESH_ASSERT_FP_EQUAL(3, test_two(0), 1.e-12);
104  LIBMESH_ASSERT_FP_EQUAL(3, test_two(2), 1.e-12);
105  LIBMESH_ASSERT_FP_EQUAL(3, test_two(4), 1.e-12);
106  LIBMESH_ASSERT_FP_EQUAL(2, test_two(5), 1.e-12);
107  LIBMESH_ASSERT_FP_EQUAL(2, test_two(1), 1.e-12);
108  LIBMESH_ASSERT_FP_EQUAL(2, test_two(3), 1.e-12);
109  LIBMESH_ASSERT_FP_EQUAL(1, test_two(6), 1.e-12);
110  LIBMESH_ASSERT_FP_EQUAL(1, test_two(7), 1.e-12);
111  }
112 
114  {
115 #ifdef LIBMESH_HAVE_FPARSER
116  LOG_UNIT_TEST;
117 
118  // We'll test the order of adding these functions to
119  // make sure time dependence gets detected/updated correctly
120  // for each
121  ParsedFunction<Real> no_t("x*2+y^2-tanh(z)+atan(x-y)");
122  ParsedFunction<Real> no_t2("x*2+y^2+z^2");
123 
125 
126  ParsedFunction<Real> xyt("x+y+t");
127 
128  // Test constructing AnalyticFunction with lambda.
129  auto af_lambda =
130  [](const Point & p, const Real t) -> Real
131  { return p(0)*p(0) + p(1)*p(1) + t*t; };
132  AnalyticFunction<Real> x2y2t2(af_lambda);
133 
134  std::vector<unsigned int> index_set(1,0);
135 
136  {
137  // composite should not be time dependent since this is the first subfunction
138  // added and it's not time-dependent
139  CompositeFunction<Real> composite;
140  composite.attach_subfunction(no_t, index_set);
141  CPPUNIT_ASSERT(!composite.is_time_dependent());
142 
143  // Now composite should be time-dependent since we've now added a time dependent function
144  index_set[0] = 1;
145  composite.attach_subfunction(xyt, index_set);
146  CPPUNIT_ASSERT(composite.is_time_dependent());
147 
148  // Composite should still be time-dependent
149  index_set[0] = 2;
150 
151  // Test AnalyticFunction copy ctor and copy assignment
152  AnalyticFunction<Real> x2y2t2_copy1(x2y2t2);
153  AnalyticFunction<Real> x2y2t2_copy2([](const Point &, const Real) -> Real { return 0; });
154  x2y2t2_copy2 = x2y2t2_copy1;
155  composite.attach_subfunction(x2y2t2_copy2, index_set);
156  CPPUNIT_ASSERT(composite.is_time_dependent());
157  }
158 
159 
160  {
161  CompositeFunction<Real> composite;
162 
163  // composite should be time-dependent since we've added a time dependent function
164  index_set[0] = 0;
165  composite.attach_subfunction(xyt, index_set);
166  CPPUNIT_ASSERT(composite.is_time_dependent());
167 
168  // composite should still be time-dependent since the previous function was time-dependent
169  index_set[0] = 1;
170  composite.attach_subfunction(no_t, index_set);
171  CPPUNIT_ASSERT(composite.is_time_dependent());
172 
173  // Composite should still be time-dependent
174  index_set[0] = 2;
175 
176  // Test AnalyticFunction move ctor and move assignment. Note: we
177  // first copy and then steal the copy's resources to avoid
178  // messing with any later tests of "x2y2t2".
179  AnalyticFunction<Real> x2y2t2_copy(x2y2t2);
180  AnalyticFunction<Real> x2y2t2_move1(std::move(x2y2t2_copy));
181  AnalyticFunction<Real> x2y2t2_move2([](const Point &, const Real) -> Real { return 0; });
182  x2y2t2_move2 = std::move(x2y2t2_move1);
183  composite.attach_subfunction(x2y2t2_move2, index_set);
184  CPPUNIT_ASSERT(composite.is_time_dependent());
185  }
186 
187  {
188  CompositeFunction<Real> composite;
189 
190  // composite should not be time-dependent since we've added a time independent function
191  index_set[0] = 0;
192  composite.attach_subfunction(no_t, index_set);
193  CPPUNIT_ASSERT(!composite.is_time_dependent());
194 
195  // composite should still be time-independent
196  index_set[0] = 1;
197  composite.attach_subfunction(no_t2, index_set);
198  CPPUNIT_ASSERT(!composite.is_time_dependent());
199 
200  // Composite should still be time-independent
201  index_set[0] = 2;
202  composite.attach_subfunction(zero, index_set);
203  CPPUNIT_ASSERT(!composite.is_time_dependent());
204  }
205 #endif // #ifdef LIBMESH_HAVE_FPARSER
206  }
207 };
208 
ConstFunction that simply returns 0.
Definition: zero_function.h:38
A Function generated (via FParser) by parsing a mathematical expression.
The libMesh namespace provides an interface to certain functionality in the library.
const Number zero
.
Definition: libmesh.h:280
Wraps a function pointer into a FunctionBase object.
A function that returns a vector whose components are defined by multiple functions.
bool is_time_dependent() const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
CPPUNIT_TEST_SUITE_REGISTRATION(CompositeFunctionTest)
Function that returns a single value that never changes.
Defines a dense vector for use in Finite Element-type computations.
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
void attach_subfunction(const FunctionBase< Output > &f, std::vector< unsigned int > index_map)
Attach a new subfunction, along with a map from the indices of the attached subfunction to the indice...