Line data Source code
1 : /*
2 : * Copyright (c) 2011-2015: G-CSC, Goethe University Frankfurt
3 : * Author: Andreas Vogel
4 : *
5 : * This file is part of UG4.
6 : *
7 : * UG4 is free software: you can redistribute it and/or modify it under the
8 : * terms of the GNU Lesser General Public License version 3 (as published by the
9 : * Free Software Foundation) with the following additional attribution
10 : * requirements (according to LGPL/GPL v3 §7):
11 : *
12 : * (1) The following notice must be displayed in the Appropriate Legal Notices
13 : * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14 : *
15 : * (2) The following notice must be displayed at a prominent place in the
16 : * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17 : *
18 : * (3) The following bibliography is recommended for citation and must be
19 : * preserved in all covered files:
20 : * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21 : * parallel geometric multigrid solver on hierarchically distributed grids.
22 : * Computing and visualization in science 16, 4 (2013), 151-164"
23 : * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24 : * flexible software system for simulating pde based models on high performance
25 : * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26 : *
27 : * This program is distributed in the hope that it will be useful,
28 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 : * GNU Lesser General Public License for more details.
31 : */
32 :
33 : #ifndef __H__UG__LIB_DISC__SPATIAL_DISC__USER_DATA__USER_DATA_IMPL__
34 : #define __H__UG__LIB_DISC__SPATIAL_DISC__USER_DATA__USER_DATA_IMPL__
35 :
36 : #include "user_data.h"
37 : #include "lib_disc/common/groups_util.h"
38 :
39 : namespace ug{
40 :
41 : ////////////////////////////////////////////////////////////////////////////////
42 : // ICplUserData
43 : ////////////////////////////////////////////////////////////////////////////////
44 :
45 : template <int dim>
46 0 : ICplUserData<dim>::ICplUserData()
47 0 : : m_locPosDim(-1), m_timePoint(0), m_defaultTimePoint(-1), m_si(-1)
48 : {
49 : m_vNumIP.clear();
50 : m_vMayChange.clear();
51 : m_pvLocIP1d.clear(); m_pvLocIP2d.clear(); m_pvLocIP3d.clear();
52 0 : m_vTime.clear(); m_vTime.push_back(0.0);
53 0 : }
54 :
55 : template <int dim>
56 0 : void ICplUserData<dim>::clear()
57 : {
58 0 : local_ip_series_to_be_cleared();
59 : m_vNumIP.clear();
60 : m_vMayChange.clear();
61 0 : m_locPosDim = -1;
62 : m_pvLocIP1d.clear(); m_pvLocIP2d.clear(); m_pvLocIP3d.clear();
63 0 : m_timePoint = 0;
64 0 : m_vTime.clear(); m_vTime.push_back(0.0);
65 0 : m_si = -1;
66 0 : }
67 :
68 : template <int dim>
69 : template <int ldim>
70 0 : size_t ICplUserData<dim>::register_local_ip_series(const MathVector<ldim>* vPos,
71 : const size_t numIP,
72 : const int timePointSpec,
73 : bool bMayChange)
74 : {
75 : // check, that dimension is ok.
76 0 : if(m_locPosDim == -1) m_locPosDim = ldim;
77 0 : else if(m_locPosDim != ldim)
78 0 : UG_THROW("Local IP dimension conflict");
79 :
80 : // get the "right" time point specification
81 0 : int theTimePoint = (m_defaultTimePoint >= 0)? m_defaultTimePoint : timePointSpec;
82 :
83 : // get local positions
84 : std::vector<const MathVector<ldim>*>& vvIP = get_local_ips(Int2Type<ldim>());
85 :
86 : // search for ips
87 : // we only identify ip series if the local ip positions will not change
88 0 : if(!bMayChange && numIP != 0)
89 0 : for(size_t s = 0; s < vvIP.size(); ++s)
90 : {
91 : // return series number iff exists and local ips remain constant
92 0 : if(!m_vMayChange[s])
93 0 : if(vvIP[s] == vPos && m_vNumIP[s] == numIP && m_vTimePoint[s] == theTimePoint)
94 0 : return s;
95 : }
96 :
97 : // if series not yet registered, add it
98 0 : vvIP.push_back(vPos);
99 0 : m_vNumIP.push_back(numIP);
100 0 : m_vTimePoint.push_back(theTimePoint);
101 0 : m_vMayChange.push_back(bMayChange);
102 :
103 : // invoke callback:
104 : // This callback is called, whenever the local_ip_series have changed. It
105 : // allows derived classes to react on this changes. For example, the data
106 : // linker must himself request local_ip_series from the data inputs of
107 : // the linker. In addition value fields and derivative fields must be adjusted
108 : // in UserData<TData, dim> etc.
109 0 : local_ip_series_added(m_vNumIP.size() - 1);
110 :
111 : // return new series id
112 0 : return m_vNumIP.size() - 1;
113 : }
114 :
115 :
116 : template <int dim>
117 : template <int ldim>
118 0 : void ICplUserData<dim>::set_local_ips(const size_t seriesID,
119 : const MathVector<ldim>* vPos,
120 : const size_t numIP)
121 : {
122 : // check series id
123 0 : if(seriesID >= num_series())
124 0 : UG_THROW("Trying to set new ips for invalid seriesID "<<seriesID);
125 :
126 : // check that series is changeable
127 0 : if(!m_vMayChange[seriesID])
128 0 : UG_THROW("Local IP is not changable, but trying to set new ips.");
129 :
130 : // check, that dimension is ok.
131 0 : if(m_locPosDim == -1) m_locPosDim = ldim;
132 0 : else if(m_locPosDim != ldim)
133 0 : UG_THROW("Local IP dimension conflict");
134 :
135 : // get local positions
136 : std::vector<const MathVector<ldim>*>& vvIP = get_local_ips(Int2Type<ldim>());
137 :
138 : // check if still at same position and with same numIP. In that case the
139 : // positions have not changed. We have nothing to do
140 0 : if(vvIP[seriesID] == vPos && m_vNumIP[seriesID] == numIP) return;
141 :
142 : // remember new positions and numIP
143 0 : vvIP[seriesID] = vPos;
144 0 : m_vNumIP[seriesID] = numIP;
145 :
146 : // invoke callback:
147 : // This callback is called, whenever the local_ip_series have changed. It
148 : // allows derived classes to react on this changes. For example, the data
149 : // linker must himself request local_ip_series from the data inputs of
150 : // the linker. In addition value fields and derivative fields must be adjusted
151 : // in UserData<TData, dim> etc.
152 0 : local_ips_changed(seriesID, numIP);
153 : }
154 :
155 : template <int dim>
156 0 : void ICplUserData<dim>::set_time_point(const size_t seriesID,
157 : const int timePointSpec)
158 : {
159 : // check series id
160 0 : if(seriesID >= num_series())
161 0 : UG_THROW("Trying to set new ips for invalid seriesID "<<seriesID);
162 :
163 : // check that series is changeable
164 0 : if(!m_vMayChange[seriesID])
165 0 : UG_THROW("Time point specification is not changable, but trying to set a new one.");
166 :
167 : // set the new time point specification (if it is not prescribed by the object)
168 0 : m_vTimePoint[seriesID] = (m_defaultTimePoint >= 0)? m_defaultTimePoint : timePointSpec;
169 :
170 : //TODO: Should we call the callback here? (No data sizes are changed!)
171 0 : }
172 :
173 : template <int dim>
174 : template <int ldim>
175 0 : const MathVector<ldim>* ICplUserData<dim>::local_ips(size_t s) const
176 : {
177 : // check, that dimension is ok.
178 0 : if(m_locPosDim != ldim) UG_THROW("Local IP dimension conflict");
179 :
180 : UG_ASSERT(s < num_series(), "Wrong series id");
181 :
182 : // NOTE: local ips may be NULL, if no ip position given, i.e. num_ip(s) == 0
183 0 : return get_local_ips(Int2Type<ldim>())[s];
184 : }
185 :
186 : template <int dim>
187 : template <int ldim>
188 : const MathVector<ldim>& ICplUserData<dim>::local_ip(size_t s, size_t ip) const
189 : {
190 : // check, that dimension is ok.
191 : if(m_locPosDim != ldim) UG_THROW("Local IP dimension conflict");
192 :
193 : UG_ASSERT(s < num_series(), "Wrong series id");
194 : UG_ASSERT(ip < num_ip(s), "Invalid index.");
195 :
196 : return get_local_ips(Int2Type<ldim>())[s][ip];
197 : }
198 :
199 : template <int dim>
200 : int ICplUserData<dim>::time_point_specification(size_t s) const
201 : {
202 : UG_ASSERT(s < num_series(), "Wrong series id");
203 :
204 : return m_vTimePoint[s];
205 : }
206 :
207 : template <int dim>
208 : size_t ICplUserData<dim>::time_point(size_t s) const
209 : {
210 : UG_ASSERT(s < num_series(), "Wrong series id:" << s << ">=" << num_series());
211 :
212 : // size_t time_spec;
213 : // if ((time_spec = m_vTimePoint[s]) >= 0)
214 0 : if (m_vTimePoint[s] >= 0)
215 0 : return m_vTimePoint[s];
216 0 : return m_timePoint;
217 : }
218 :
219 : template <int dim>
220 : bool ICplUserData<dim>::at_current_time(size_t s) const
221 : {
222 : UG_ASSERT(s < num_series(), "Wrong series id:" << s << ">=" << num_series());
223 :
224 : int time_spec;
225 0 : if ((time_spec = m_vTimePoint[s]) >= 0)
226 0 : return ((size_t) time_spec) == m_timePoint;
227 : return true;
228 : }
229 :
230 : template <int dim>
231 0 : void ICplUserData<dim>::set_global_ips(size_t s, const MathVector<dim>* vPos, size_t numIP)
232 : {
233 : UG_ASSERT(s < num_series(), "Wrong series id: "<<s<<" (numSeries: "<<num_series()<<")");
234 :
235 : // check number of ips (must match local ip number)
236 0 : if(numIP != num_ip(s))
237 0 : UG_THROW("UserData::set_global_ips: Num Local IPs is " << num_ip(s)
238 : << ", but trying to set Num Global IPs: " << numIP <<
239 : " for series "<< s);
240 :
241 : // remember global positions
242 0 : m_vvGlobPos[s] = vPos;
243 :
244 : // invoke callback:
245 : // this callback is called every time the global position changes. It gives
246 : // derived classes the possibility to react on this fact. E.g. the data
247 : // linker must forward the global positions to its own imports.
248 0 : global_ips_changed(s, vPos, numIP);
249 0 : }
250 :
251 : template <int dim>
252 : inline void ICplUserData<dim>::check_s(size_t s) const
253 : {
254 : UG_ASSERT(s < num_series(), "Wrong series id");
255 : UG_ASSERT(s < m_vvGlobPos.size(), "Invalid index.");
256 : }
257 :
258 : template <int dim>
259 : inline void ICplUserData<dim>::check_s_ip(size_t s, size_t ip) const
260 : {
261 : check_s(s);
262 : UG_ASSERT(ip < num_ip(s), "Invalid index.");
263 : UG_ASSERT(m_vvGlobPos[s] != NULL, "Global IP not set.");
264 : }
265 :
266 : ////////////////////////////////////////////////////////////////////////////////
267 : // UserData
268 : ////////////////////////////////////////////////////////////////////////////////
269 :
270 : template <typename TData, int dim, typename TRet>
271 0 : void CplUserData<TData,dim,TRet>::
272 : register_storage_callback(DataImport<TData,dim>* obj, void (DataImport<TData,dim>::*func)())
273 : {
274 : typedef std::pair<DataImport<TData,dim>*, CallbackFct> Pair;
275 : // m_vCallback.push_back(Pair(obj,func));
276 0 : m_vCallback.push_back(Pair(obj, std::bind(func, obj)));
277 0 : }
278 :
279 : template <typename TData, int dim, typename TRet>
280 0 : void CplUserData<TData,dim,TRet>::
281 : unregister_storage_callback(DataImport<TData,dim>* obj)
282 : {
283 : typedef typename std::vector<std::pair<DataImport<TData,dim>*, CallbackFct> > VecType;
284 : typedef typename VecType::iterator iterator;
285 : iterator iter = m_vCallback.begin();
286 0 : while(iter != m_vCallback.end())
287 : {
288 0 : if((*iter).first == obj) iter = m_vCallback.erase(iter);
289 : else ++iter;
290 : }
291 0 : }
292 :
293 : template <typename TData, int dim, typename TRet>
294 0 : void CplUserData<TData,dim,TRet>::
295 : call_storage_callback() const
296 : {
297 : typedef typename std::vector<std::pair<DataImport<TData,dim>*, CallbackFct> > VecType;
298 : typedef typename VecType::const_iterator iterator;
299 0 : for(iterator iter = m_vCallback.begin(); iter != m_vCallback.end(); ++iter)
300 : {
301 : // (((*iter).first)->*((*iter).second))();
302 : ((*iter).second)();
303 : }
304 0 : }
305 :
306 : template <typename TData, int dim, typename TRet>
307 : inline void CplUserData<TData,dim,TRet>::check_series(size_t s) const
308 : {
309 : UG_ASSERT(s < num_series(), "Wrong series id"<<s);
310 : UG_ASSERT(s < m_vvValue.size(), "Invalid index "<<s);
311 : }
312 :
313 : template <typename TData, int dim, typename TRet>
314 : inline void CplUserData<TData,dim,TRet>::check_series_ip(size_t s, size_t ip) const
315 : {
316 : check_series(s);
317 : UG_ASSERT(ip < num_ip(s), "Invalid index "<<ip);
318 : UG_ASSERT(ip < m_vvValue[s].size(), "Invalid index "<<ip);
319 : }
320 :
321 : template <typename TData, int dim, typename TRet>
322 0 : void CplUserData<TData,dim,TRet>::local_ip_series_added(const size_t seriesID)
323 : {
324 : const size_t s = seriesID;
325 :
326 : // check, that only increasing the data, this is important to guarantee,
327 : // that the allocated memory pointer remain valid. They are used outside of
328 : // the class as well to allow fast access to the data.
329 0 : if(s < m_vvValue.size())
330 0 : UG_THROW("Decrease is not implemented. Series: "<<s<<
331 : ", currNumSeries: "<<m_vvValue.size());
332 :
333 : // increase number of series if needed
334 0 : m_vvValue.resize(s+1);
335 0 : m_vvBoolFlag.resize(s+1);
336 :
337 : // allocate new storage
338 0 : m_vvValue[s].resize(num_ip(s));
339 0 : m_vvBoolFlag[s].resize(num_ip(s), true);
340 0 : value_storage_changed(s);
341 0 : call_storage_callback();
342 :
343 : // call base class callback
344 : base_type::local_ip_series_added(seriesID);
345 0 : }
346 :
347 : template <typename TData, int dim, typename TRet>
348 0 : void CplUserData<TData,dim,TRet>::local_ip_series_to_be_cleared()
349 : {
350 : // free the memory
351 : // clear all series
352 : m_vvValue.clear();
353 : m_vvBoolFlag.clear();
354 :
355 : // call base class callback (if implementation given)
356 : // base_type::local_ip_series_to_be_cleared();
357 0 : }
358 :
359 : template <typename TData, int dim, typename TRet>
360 0 : void CplUserData<TData,dim,TRet>::local_ips_changed(const size_t seriesID, const size_t newNumIP)
361 : {
362 : // resize only when more data is needed than actually allocated
363 0 : if(newNumIP >= m_vvValue[seriesID].size())
364 : {
365 : // resize
366 0 : m_vvValue[seriesID].resize(newNumIP);
367 0 : m_vvBoolFlag[seriesID].resize(newNumIP, true);
368 :
369 : // invoke callback
370 0 : value_storage_changed(seriesID);
371 0 : call_storage_callback();
372 : }
373 :
374 : // call base class callback (if implementation given)
375 : // base_type::local_ips_changed(seriesID);
376 0 : }
377 :
378 : ////////////////////////////////////////////////////////////////////////////////
379 : // DependentUserData
380 : ////////////////////////////////////////////////////////////////////////////////
381 :
382 : template <typename TData, int dim>
383 0 : void DependentUserData<TData,dim>::set_function_pattern(ConstSmartPtr<FunctionPattern> fctPatt)
384 : {
385 0 : this->m_fctGrp.set_function_pattern(fctPatt);
386 0 : extract_fct_grp();
387 0 : }
388 :
389 : template <typename TData, int dim>
390 0 : void DependentUserData<TData,dim>::set_functions(const char* symbFct)
391 : {
392 0 : set_functions(std::string(symbFct));
393 0 : }
394 :
395 : template <typename TData, int dim>
396 0 : void DependentUserData<TData,dim>::set_functions(const std::string& symbFct)
397 : {
398 0 : set_functions(TokenizeTrimString(symbFct));
399 0 : }
400 :
401 : template <typename TData, int dim>
402 : void DependentUserData<TData,dim>::set_functions(const std::vector<std::string>& symbFct)
403 : {
404 0 : m_SymbFct = symbFct;
405 0 : extract_fct_grp();
406 0 : }
407 :
408 : template <typename TData, int dim>
409 0 : void DependentUserData<TData,dim>::extract_fct_grp()
410 : {
411 : // if associated infos missing return
412 0 : ConstSmartPtr<FunctionPattern> spFctPatt = this->m_fctGrp.function_pattern();
413 0 : if(spFctPatt.invalid()) return;
414 :
415 : // if no function passed, clear functions
416 0 : if(m_SymbFct.size() == 1 && m_SymbFct[0].empty()) m_SymbFct.clear();
417 :
418 : // if functions passed with separator, but not all tokens filled, throw error
419 0 : for(size_t i = 0; i < m_SymbFct.size(); ++i)
420 : {
421 0 : if(m_SymbFct.empty())
422 0 : UG_THROW("Error while setting functions in a DependentUserData: passed "
423 : "function string lacks a "
424 : "function specification at position "<<i<<"(of "
425 : <<m_SymbFct.size()-1<<")");
426 : }
427 :
428 0 : if(m_SymbFct.empty()){
429 0 : this->m_fctGrp.clear();
430 0 : return;
431 : }
432 :
433 : // create function group of this elem disc
434 : try{
435 0 : this->m_fctGrp.clear();
436 0 : this->m_fctGrp.add(m_SymbFct);
437 0 : }UG_CATCH_THROW("DependentUserData: Cannot find some symbolic function "
438 : "name.");
439 :
440 : // create a mapping between all functions and the function group of this
441 : // element disc.
442 : try{
443 0 : CreateFunctionIndexMapping(this->m_map, this->m_fctGrp, spFctPatt);
444 0 : }UG_CATCH_THROW("DependentUserData: Cannot create Function Index Mapping.");
445 :
446 0 : this->check_setup();
447 : }
448 :
449 : template <typename TData, int dim>
450 0 : void DependentUserData<TData,dim>::update_dof_sizes(const LocalIndices& ind)
451 : {
452 : // check size
453 0 : const FunctionIndexMapping& map = this->map();
454 : UG_ASSERT(map.num_fct() == this->num_fct(), "Number function mismatch.");
455 :
456 : // cache numFct and their numDoFs
457 0 : m_vvNumDoFPerFct.resize(map.num_fct());
458 0 : for(size_t fct = 0; fct < m_vvNumDoFPerFct.size(); ++fct)
459 0 : m_vvNumDoFPerFct[fct] = ind.num_dof(map[fct]);
460 :
461 : resize_deriv_array();
462 0 : }
463 :
464 : template <typename TData, int dim>
465 : void DependentUserData<TData,dim>::resize_deriv_array()
466 : {
467 : // resize num fct
468 0 : for(size_t s = 0; s < m_vvvvDeriv.size(); ++s)
469 0 : resize_deriv_array(s);
470 : }
471 :
472 : template <typename TData, int dim>
473 0 : void DependentUserData<TData,dim>::resize_deriv_array(const size_t s)
474 : {
475 : // resize ips
476 0 : m_vvvvDeriv[s].resize(num_ip(s));
477 :
478 0 : for(size_t ip = 0; ip < m_vvvvDeriv[s].size(); ++ip)
479 : {
480 : // resize num fct
481 0 : m_vvvvDeriv[s][ip].resize(m_vvNumDoFPerFct.size());
482 :
483 : // resize dofs
484 0 : for(size_t fct = 0; fct < m_vvNumDoFPerFct.size(); ++fct)
485 0 : m_vvvvDeriv[s][ip][fct].resize(m_vvNumDoFPerFct[fct]);
486 : }
487 0 : }
488 :
489 : template <typename TData, int dim>
490 0 : void DependentUserData<TData,dim>::set_zero(std::vector<std::vector<TData> > vvvDeriv[], const size_t nip)
491 : {
492 0 : for(size_t ip = 0; ip < nip; ++ip)
493 0 : for(size_t fct = 0; fct < vvvDeriv[ip].size(); ++fct)
494 0 : for(size_t sh = 0; sh < vvvDeriv[ip][fct].size(); ++sh)
495 : {
496 0 : vvvDeriv[ip][fct][sh] = 0.0;
497 : }
498 0 : }
499 :
500 : template <typename TData, int dim>
501 : inline void DependentUserData<TData,dim>::check_s_ip(size_t s, size_t ip) const
502 : {
503 : UG_ASSERT(s < this->num_series(), "Wrong series id"<<s);
504 : UG_ASSERT(s < m_vvvvDeriv.size(), "Invalid index "<<s);
505 : UG_ASSERT(ip < this->num_ip(s), "Invalid index "<<ip);
506 : UG_ASSERT(ip < m_vvvvDeriv[s].size(), "Invalid index "<<ip);
507 : }
508 :
509 : template <typename TData, int dim>
510 : inline void DependentUserData<TData,dim>::check_s_ip_fct(size_t s, size_t ip, size_t fct) const
511 : {
512 : check_s_ip(s,ip);
513 : UG_ASSERT(fct < m_vvvvDeriv[s][ip].size(), "Invalid index.");
514 : }
515 :
516 : template <typename TData, int dim>
517 : inline void DependentUserData<TData,dim>::check_s_ip_fct_dof(size_t s, size_t ip, size_t fct, size_t dof) const
518 : {
519 : check_s_ip_fct(s,ip,fct);
520 : UG_ASSERT(dof < m_vvvvDeriv[s][ip][fct].size(), "Invalid index.");
521 : }
522 :
523 : template <typename TData, int dim>
524 0 : void DependentUserData<TData,dim>::local_ip_series_added(const size_t seriesID)
525 : {
526 : // adjust data arrays
527 0 : m_vvvvDeriv.resize(seriesID+1);
528 :
529 : // forward change signal to base class
530 0 : base_type::local_ip_series_added(seriesID);
531 0 : }
532 :
533 : template <typename TData, int dim>
534 0 : void DependentUserData<TData,dim>::local_ip_series_to_be_cleared()
535 : {
536 : // adjust data arrays
537 : m_vvvvDeriv.clear();
538 :
539 : // forward change signal to base class
540 0 : base_type::local_ip_series_to_be_cleared();
541 0 : }
542 :
543 : template <typename TData, int dim>
544 0 : void DependentUserData<TData,dim>::local_ips_changed(const size_t seriesID, const size_t newNumIP)
545 : {
546 : UG_ASSERT(seriesID < m_vvvvDeriv.size(), "wrong series id.");
547 :
548 : // resize only when more data is needed than actually allocated
549 0 : if(newNumIP >= m_vvvvDeriv[seriesID].size())
550 0 : resize_deriv_array(seriesID);
551 :
552 : // call base class callback (if implementation given)
553 0 : base_type::local_ips_changed(seriesID, newNumIP);
554 0 : }
555 :
556 : } // end namespace ug
557 :
558 : #endif /* __H__UG__LIB_DISC__SPATIAL_DISC__USER_DATA__USER_DATA_IMPL__ */
|