BEM++  2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
nonseparable_numerical_test_kernel_trial_integrator_imp.hpp
1 // Copyright (C) 2011-2012 by the BEM++ Authors
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 // THE SOFTWARE.
20 
21 #include "../common/common.hpp"
22 
23 #include "nonseparable_numerical_test_kernel_trial_integrator.hpp" // To keep IDEs happy
24 
25 #include "_3d_array.hpp"
26 #include "_4d_array.hpp"
27 #include "collection_of_3d_arrays.hpp"
28 #include "collection_of_4d_arrays.hpp"
29 
30 #include "basis.hpp"
31 #include "basis_data.hpp"
32 #include "conjugate.hpp"
33 #include "collection_of_basis_transformations.hpp"
34 #include "geometrical_data.hpp"
35 #include "collection_of_kernels.hpp"
36 #include "opencl_handler.hpp"
37 #include "raw_grid_geometry.hpp"
38 #include "test_kernel_trial_integral.hpp"
39 #include "types.hpp"
40 
41 #include <cassert>
42 #include <iostream>
43 #include <memory>
44 
45 namespace Fiber
46 {
47 
48 template <typename BasisFunctionType, typename KernelType,
49  typename ResultType, typename GeometryFactory>
50 NonseparableNumericalTestKernelTrialIntegrator<
51 BasisFunctionType, KernelType, ResultType, GeometryFactory>::
52 NonseparableNumericalTestKernelTrialIntegrator(
53  const arma::Mat<CoordinateType>& localTestQuadPoints,
54  const arma::Mat<CoordinateType>& localTrialQuadPoints,
55  const std::vector<CoordinateType> quadWeights,
56  const GeometryFactory& testGeometryFactory,
57  const GeometryFactory& trialGeometryFactory,
58  const RawGridGeometry<CoordinateType>& testRawGeometry,
59  const RawGridGeometry<CoordinateType>& trialRawGeometry,
60  const CollectionOfShapesetTransformations<CoordinateType>& testTransformations,
61  const CollectionOfKernels<KernelType>& kernels,
62  const CollectionOfShapesetTransformations<CoordinateType>& trialTransformations,
63  const TestKernelTrialIntegral<BasisFunctionType, KernelType, ResultType>& integral,
64  const OpenClHandler& openClHandler) :
65  m_localTestQuadPoints(localTestQuadPoints),
66  m_localTrialQuadPoints(localTrialQuadPoints),
67  m_quadWeights(quadWeights),
68  m_testGeometryFactory(testGeometryFactory),
69  m_trialGeometryFactory(trialGeometryFactory),
70  m_testRawGeometry(testRawGeometry),
71  m_trialRawGeometry(trialRawGeometry),
72  m_testTransformations(testTransformations),
73  m_kernels(kernels),
74  m_trialTransformations(trialTransformations),
75  m_integral(integral),
76  m_openClHandler(openClHandler)
77 {
78  const size_t pointCount = quadWeights.size();
79  if (localTestQuadPoints.n_cols != pointCount ||
80  localTrialQuadPoints.n_cols != pointCount)
81  throw std::invalid_argument("NonseparableNumericalTestKernelTrialIntegrator::"
82  "NonseparableNumericalTestKernelTrialIntegrator(): "
83  "numbers of points and weights do not match");
84 }
85 
86 template <typename BasisFunctionType, typename KernelType,
87  typename ResultType, typename GeometryFactory>
88 NonseparableNumericalTestKernelTrialIntegrator<
89 BasisFunctionType, KernelType, ResultType, GeometryFactory>::
90 ~NonseparableNumericalTestKernelTrialIntegrator()
91 {
92  // Note: obviously the destructor is assumed to be called only after
93  // all threads have ceased using the integrator!
94 
95  for (typename BasisDataCache::const_iterator it = m_cachedTestBasisData.begin();
96  it != m_cachedTestBasisData.end(); ++it)
97  delete it->second;
98  m_cachedTestBasisData.clear();
99  for (typename BasisDataCache::const_iterator it = m_cachedTrialBasisData.begin();
100  it != m_cachedTrialBasisData.end(); ++it)
101  delete it->second;
102  m_cachedTrialBasisData.clear();
103 }
104 
105 template <typename BasisFunctionType, typename KernelType,
106  typename ResultType, typename GeometryFactory>
107 const BasisData<BasisFunctionType>&
108 NonseparableNumericalTestKernelTrialIntegrator<
109 BasisFunctionType, KernelType, ResultType, GeometryFactory>::
110 basisData(ElementType type, const Shapeset<BasisFunctionType>& shapeset) const
111 {
112  BasisDataCache& cache =
113  type == TEST ? m_cachedTestBasisData : m_cachedTrialBasisData;
114  const CollectionOfShapesetTransformations<CoordinateType>& transformations =
115  type == TEST ? m_testTransformations : m_trialTransformations;
116  const arma::Mat<CoordinateType>& localQuadPoints =
117  type == TEST ? m_localTestQuadPoints : m_localTrialQuadPoints;
118 
119  typename BasisDataCache::iterator it = cache.find(&shapeset);
120  if (it == cache.end()) {
121  // FIXME: At the beginning of each loop, all threads want to calculate
122  // these basis data. It would be good to do singular integral
123  // calculation in such a way that all types would be merged in a single
124  // parallel loop; this should solve this problem.
125 
126  // Need to calculate basis data from scratch
127  std::auto_ptr<BasisData<BasisFunctionType> > basisData(
128  new BasisData<BasisFunctionType>);
129  size_t basisDeps = 0, geomDeps = 0;
130  transformations.addDependencies(basisDeps, geomDeps);
131  shapeset.evaluate(basisDeps, localQuadPoints, ALL_DOFS, *basisData);
132 
133  // Release the newly created basis data object from the auto pointer and
134  // try to insert it into the map. If the insertion succeeds, the map
135  // takes ownership of the object, which will be deleted in the
136  // destructor of the integrator. If the insertion fails, it means
137  // another thread has already inserted the basis data for this shapeset,
138  // so our basis data object is now redundant and should be released.
139  BasisData<BasisFunctionType>* ptrBasisData = basisData.release();
140  std::pair<typename BasisDataCache::iterator, bool> result =
141  cache.insert(std::make_pair(&shapeset, ptrBasisData));
142  it = result.first; // this is the object that ended up into the cache
143  if (!result.second) // insertion failed
144  delete ptrBasisData;
145  }
146  return *it->second;
147 }
148 
149 template <typename BasisFunctionType, typename KernelType,
150  typename ResultType, typename GeometryFactory>
151 void
152 NonseparableNumericalTestKernelTrialIntegrator<
153 BasisFunctionType, KernelType, ResultType, GeometryFactory>::
154 integrate(
155  CallVariant callVariant,
156  const std::vector<int>& elementIndicesA,
157  int elementIndexB,
158  const Shapeset<BasisFunctionType>& basisA,
159  const Shapeset<BasisFunctionType>& basisB,
160  LocalDofIndex localDofIndexB,
161  const std::vector<arma::Mat<ResultType>*>& result) const
162 {
163  const int pointCount = m_quadWeights.size();
164  const int elementACount = elementIndicesA.size();
165 
166  if (result.size() != elementIndicesA.size())
167  throw std::invalid_argument(
168  "NonseparableNumericalTestKernelTrialIntegrator::integrate(): "
169  "arrays 'result' and 'elementIndicesA' must have the same number "
170  "of elements");
171  if (pointCount == 0 || elementACount == 0)
172  return;
173  // TODO: in the (pathological) case that pointCount == 0 but
174  // geometryCount != 0, set elements of result to 0.
175 
176  // Evaluate constants
177 
178  const int dofCountA = basisA.size();
179  const int dofCountB = localDofIndexB == ALL_DOFS ? basisB.size() : 1;
180  const int testDofCount = callVariant == TEST_TRIAL ? dofCountA : dofCountB;
181  const int trialDofCount = callVariant == TEST_TRIAL ? dofCountB : dofCountA;
182 
183  BasisData<BasisFunctionType> testBasisData, trialBasisData;
184  GeometricalData<CoordinateType>& testGeomData = m_testGeomData.local();
185  GeometricalData<CoordinateType>& trialGeomData = m_trialGeomData.local();
186 
187  size_t testBasisDeps = 0, trialBasisDeps = 0;
188  size_t testGeomDeps = 0, trialGeomDeps = 0;
189 
190  m_testTransformations.addDependencies(testBasisDeps, testGeomDeps);
191  m_trialTransformations.addDependencies(trialBasisDeps, trialGeomDeps);
192  m_kernels.addGeometricalDependencies(testGeomDeps, trialGeomDeps);
193  m_integral.addGeometricalDependencies(testGeomDeps, trialGeomDeps);
194 
195  typedef typename GeometryFactory::Geometry Geometry;
196 
197  std::auto_ptr<Geometry> geometryA, geometryB;
198  const RawGridGeometry<CoordinateType> *rawGeometryA = 0, *rawGeometryB = 0;
199  if (callVariant == TEST_TRIAL)
200  {
201  geometryA = m_testGeometryFactory.make();
202  geometryB = m_trialGeometryFactory.make();
203  rawGeometryA = &m_testRawGeometry;
204  rawGeometryB = &m_trialRawGeometry;
205  }
206  else
207  {
208  geometryA = m_trialGeometryFactory.make();
209  geometryB = m_testGeometryFactory.make();
210  rawGeometryA = &m_trialRawGeometry;
211  rawGeometryB = &m_testRawGeometry;
212  }
213 
214  CollectionOf3dArrays<BasisFunctionType> testValues, trialValues;
215  CollectionOf3dArrays<KernelType> kernelValues;
216 
217  for (size_t i = 0; i < result.size(); ++i) {
218  assert(result[i]);
219  result[i]->set_size(testDofCount, trialDofCount);
220  }
221 
222  rawGeometryB->setupGeometry(elementIndexB, *geometryB);
223  if (callVariant == TEST_TRIAL)
224  {
225  basisA.evaluate(testBasisDeps, m_localTestQuadPoints, ALL_DOFS, testBasisData);
226  basisB.evaluate(trialBasisDeps, m_localTrialQuadPoints, localDofIndexB, trialBasisData);
227  geometryB->getData(trialGeomDeps, m_localTrialQuadPoints, trialGeomData);
228  m_trialTransformations.evaluate(trialBasisData, trialGeomData, trialValues);
229  }
230  else
231  {
232  basisA.evaluate(trialBasisDeps, m_localTrialQuadPoints, ALL_DOFS, trialBasisData);
233  basisB.evaluate(testBasisDeps, m_localTestQuadPoints, localDofIndexB, testBasisData);
234  geometryB->getData(testGeomDeps, m_localTestQuadPoints, testGeomData);
235  m_testTransformations.evaluate(testBasisData, testGeomData, testValues);
236  }
237 
238  // Iterate over the elements
239  for (int indexA = 0; indexA < elementACount; ++indexA)
240  {
241  rawGeometryA->setupGeometry(elementIndicesA[indexA], *geometryA);
242  if (callVariant == TEST_TRIAL)
243  {
244  geometryA->getData(testGeomDeps, m_localTestQuadPoints, testGeomData);
245  m_testTransformations.evaluate(testBasisData, testGeomData, testValues);
246  }
247  else
248  {
249  geometryA->getData(trialGeomDeps, m_localTrialQuadPoints, trialGeomData);
250  m_trialTransformations.evaluate(trialBasisData, trialGeomData, trialValues);
251  }
252 
253  m_kernels.evaluateAtPointPairs(testGeomData, trialGeomData, kernelValues);
254  m_integral.evaluateWithNontensorQuadratureRule(
255  testGeomData, trialGeomData, testValues, trialValues,
256  kernelValues, m_quadWeights,
257  *result[indexA]);
258  }
259 }
260 
261 template <typename BasisFunctionType, typename KernelType,
262  typename ResultType, typename GeometryFactory>
263 void
264 NonseparableNumericalTestKernelTrialIntegrator<
265 BasisFunctionType, KernelType, ResultType, GeometryFactory>::
266 integrate(
267  const std::vector<ElementIndexPair>& elementIndexPairs,
268  const Shapeset<BasisFunctionType>& testShapeset,
269  const Shapeset<BasisFunctionType>& trialShapeset,
270  const std::vector<arma::Mat<ResultType>*>& result) const
271 {
272  const int pointCount = m_quadWeights.size();
273  const int geometryPairCount = elementIndexPairs.size();
274 
275  if (result.size() != elementIndexPairs.size())
276  throw std::invalid_argument(
277  "NonseparableNumericalTestKernelTrialIntegrator::integrate(): "
278  "arrays 'result' and 'elementIndicesA' must have the same number "
279  "of elements");
280  if (pointCount == 0 || geometryPairCount == 0)
281  return;
282  // TODO: in the (pathological) case that pointCount == 0 but
283  // geometryPairCount != 0, set elements of result to 0.
284 
285  const int testDofCount = testShapeset.size();
286  const int trialDofCount = trialShapeset.size();
287 
288  // BasisData<BasisFunctionType> testBasisData, trialBasisData;
289  const BasisData<BasisFunctionType>& testBasisData
290  = basisData(TEST, testShapeset);
291  const BasisData<BasisFunctionType>& trialBasisData
292  = basisData(TRIAL, trialShapeset);
293  GeometricalData<CoordinateType>& testGeomData = m_testGeomData.local();
294  GeometricalData<CoordinateType>& trialGeomData = m_trialGeomData.local();
295 
296  size_t testBasisDeps = 0, trialBasisDeps = 0;
297  size_t testGeomDeps = 0, trialGeomDeps = 0;
298 
299  m_testTransformations.addDependencies(testBasisDeps, testGeomDeps);
300  m_trialTransformations.addDependencies(trialBasisDeps, trialGeomDeps);
301  m_kernels.addGeometricalDependencies(testGeomDeps, trialGeomDeps);
302  m_integral.addGeometricalDependencies(testGeomDeps, trialGeomDeps);
303 
304  typedef typename GeometryFactory::Geometry Geometry;
305  std::auto_ptr<Geometry> testGeometry(m_testGeometryFactory.make());
306  std::auto_ptr<Geometry> trialGeometry(m_trialGeometryFactory.make());
307 
308  CollectionOf3dArrays<BasisFunctionType> testValues, trialValues;
309  CollectionOf3dArrays<KernelType> kernelValues;
310 
311  for (size_t i = 0; i < result.size(); ++i) {
312  assert(result[i]);
313  result[i]->set_size(testDofCount, trialDofCount);
314  }
315 
316 // testShapeset.evaluate(testBasisDeps, m_localTestQuadPoints, ALL_DOFS, testBasisData);
317 // trialShapeset.evaluate(trialBasisDeps, m_localTrialQuadPoints, ALL_DOFS, trialBasisData);
318 
319  // Iterate over the elements
320  for (int pairIndex = 0; pairIndex < geometryPairCount; ++pairIndex)
321  {
322  m_testRawGeometry.setupGeometry(elementIndexPairs[pairIndex].first, *testGeometry);
323  m_trialRawGeometry.setupGeometry(elementIndexPairs[pairIndex].second, *trialGeometry);
324  testGeometry->getData(testGeomDeps, m_localTestQuadPoints, testGeomData);
325  trialGeometry->getData(trialGeomDeps, m_localTrialQuadPoints, trialGeomData);
326  m_testTransformations.evaluate(testBasisData, testGeomData, testValues);
327  m_trialTransformations.evaluate(trialBasisData, trialGeomData, trialValues);
328 
329  m_kernels.evaluateAtPointPairs(testGeomData, trialGeomData, kernelValues);
330  m_integral.evaluateWithNontensorQuadratureRule(
331  testGeomData, trialGeomData, testValues, trialValues,
332  kernelValues, m_quadWeights,
333  *result[pairIndex]);
334  }
335 }
336 
337 } // namespace Fiber
virtual void evaluateAtPointPairs(const GeometricalData< CoordinateType > &testGeomData, const GeometricalData< CoordinateType > &trialGeomData, CollectionOf3dArrays< ValueType > &result) const =0
Evaluate the kernels at a list of (test point, trial point) pairs.
virtual void addGeometricalDependencies(size_t &testGeomDeps, size_t &trialGeomDeps) const =0
Retrieve types of geometrical data on which the kernels depend.