G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsAPALMData.hpp
Go to the documentation of this file.
1
14#pragma once
15
16namespace gismo
17{
18
19template <class T, class solution_t >
20gsAPALMData<T,solution_t>::gsAPALMData( const std::vector<T> & times,
21 const std::vector<solution_t> & solutions)
22:
23m_initialized(false),
24m_dt(1.0)
25{
26 GISMO_ASSERT(times.size()==solutions.size(),"Sizes must agree");
27
28 setData(times,solutions);
29
30 _defaultOptions();
31}
32
33template <class T, class solution_t >
34gsAPALMData<T,solution_t>::gsAPALMData(const std::vector<T> & times)
35:
36m_initialized(false),
37m_dt(1.0)
38{
39 // Initialize the knot vectors
40 m_t = gsKnotVector<T>(times);
41 m_xi = m_t;
42 m_xi.transform(0,1);
43
44 _defaultOptions();
45}
46
47template <class T, class solution_t >
48gsAPALMData<T,solution_t>::gsAPALMData()
49:
50m_initialized(false),
51m_dt(1.0)
52{
53 _defaultOptions();
54 m_t = gsKnotVector<T>(0);
55}
56
57template <class T, class solution_t >
58void gsAPALMData<T,solution_t>::_defaultOptions()
59{
60 m_maxLevel = 5;
61 m_tolerance = 1e-1;
62 m_verbose = 0;
63 m_options.addInt("MaxLevel","Sets the maximum level for hierarchical refinement",m_maxLevel);
64 m_options.addReal("Tolerance","Relative tolerance",m_tolerance);
65 m_options.addInt("Verbose","Verbosity; 0=none, 1=minimal, 2=full",m_verbose);
66}
67
68template <class T, class solution_t >
69void gsAPALMData<T,solution_t>::_applyOptions()
70{
71 m_maxLevel = m_options.getInt("MaxLevel");
72 m_tolerance = m_options.getReal("Tolerance");
73 m_verbose = m_options.getInt("Verbose");
74}
75
76
77template <class T, class solution_t >
78void gsAPALMData<T,solution_t>::init()
79{
80 this->_applyOptions();
81 // Clean queue
82 std::deque<std::tuple<T,T,index_t>> queue;
83 m_queue.swap(queue);
84
85 T low,upp;
86 for (typename gsKnotVector<T>::const_iterator it = m_xi.begin(); it != std::prev(m_xi.end()); )
87 {
88 low = *it;
89 it++;
90 upp = *it;
91 m_queue.push_back({low,upp,1});
92 }
93
94 this->_buildMap();
95
96 m_initialized = true;
97}
98
99template <class T, class solution_t >
100void gsAPALMData<T,solution_t>::addStartPoint(const T & time, const solution_t & solution, bool priority)
101{
102 GISMO_ASSERT(m_t.size()==m_xi.size(),"Sizes must be the same!");
103 GISMO_ASSERT(m_t.size()==0,"Start point can only be added in a new branch");
104 this->_applyOptions();
105 T xi = 0;
106 m_t.insert(time);
107 m_xi.insert(xi);
108
109 auto sol = std::make_shared<solution_t>(solution);
110 m_solutions.insert({xi,sol});
111 m_levels.insert({xi,0});
112
113 auto prev = std::make_shared<solution_t>(*(m_solutions[xi]).get());
114 m_prevs .insert({xi,prev});
115
116 // same start and end coordinate, will be recognized by the pop function
117 if (priority)
118 m_queue.push_front({xi,xi,0});
119 else
120 m_queue.push_back({xi,xi,0});
121 m_initialized = true;
122}
123
124template <class T, class solution_t >
125void gsAPALMData<T,solution_t>::appendPoint(bool priority)
126{
127 // same start and end coordinate, will be recognized by the pop function
128 if (priority)
129 m_queue.push_front({m_xi.last(),m_xi.last(),0});
130 else
131 m_queue.push_back({m_xi.last(),m_xi.last(),0});
132 m_initialized = true;
133}
134
135template <class T, class solution_t >
136void gsAPALMData<T,solution_t>::appendData(const T & time, const solution_t & solution, bool priority)
137{
138 // Initialize the knot vectors
139 GISMO_ASSERT(m_t.size()==m_xi.size(),"Sizes must be the same!");
140 GISMO_ASSERT(m_t.size()==0 || time>m_t.last(),"Time must be bigger than last stored time!");
141 T xi;
142 if (m_t.size()==0)
143 xi = 0;
144 else if (m_t.size()==1)
145 xi = 1;
146 else
147 xi = (time-m_t.last()) * (m_xi.last()-m_xi.first()) / (m_t.last()-m_t.first()) + m_xi.last();
148
149 auto sol = std::make_shared<solution_t>(solution);
150 m_solutions.insert({xi,sol});
151 m_levels.insert({xi,0});
152
153 // add a previous, if exists
154 if (m_t.size()==0)
155 {
156 auto prev = std::make_shared<solution_t>(*(m_solutions[xi]).get());
157 m_prevs .insert({xi,prev});
158 }
159 else
160 {
161 auto prev = std::make_shared<solution_t>(*(m_solutions[m_xi.last()]).get());
162 m_prevs .insert({xi,prev});
163 if (priority)
164 m_queue.push_front({m_xi.last(),xi,1});
165 else
166 m_queue.push_back({m_xi.last(),xi,1});
167 m_initialized = true;
168 }
169
170
171 m_t.insert(time);
172 m_xi.insert(xi);
173
174 this->_buildMap();
175}
176
177template <class T, class solution_t >
178void gsAPALMData<T,solution_t>::setData(const std::vector<T> & times,const std::vector<solution_t> & solutions)
179{
180 // Initialize the knot vectors
181 m_t = gsKnotVector<T>(times);
182 m_xi = m_t;
183 m_xi.transform(0,1);
184
185 auto sol0 = std::make_shared<solution_t>(solutions.at(0));
186 m_solutions.insert({m_xi.at(0),sol0});
187 m_levels.insert({m_xi.at(0),0});
188 auto prev0 = std::make_shared<solution_t>(*(m_solutions[m_xi.at(0)]).get());
189 m_prevs .insert({m_xi.at(0),prev0});
190 for (size_t k=1; k!=m_xi.size(); ++k)
191 {
192 auto solk = std::make_shared<solution_t>(solutions.at(k));
193 m_solutions.insert({m_xi.at(k),solk});
194 m_levels.insert({m_xi.at(k),0});
195 auto prevk = std::make_shared<solution_t>(*(m_solutions[m_xi.at(k-1)]).get());
196 m_prevs .insert({m_xi.at(k),prevk});
197 }
198}
199
200// template <class T, class solution_t >
201// void gsAPALMData<T,solution_t>::initEmptyQueue(const index_t & N)
202// {
203// setData(times,solutions);
204// init();
205// }
206
207template <class T, class solution_t >
208void gsAPALMData<T,solution_t>::init(const std::vector<T> & times,const std::vector<solution_t> & solutions)
209{
210 setData(times,solutions);
211 init();
212}
213
214template <class T, class solution_t >
215std::tuple<index_t, T , solution_t, solution_t> gsAPALMData<T,solution_t>::pop()
216{
217 GISMO_ASSERT(m_initialized,"Structure is not initialized");
218 GISMO_ASSERT(!m_queue.empty(),"The queue is empty! Something went wrong.");
219
220 T xilow = std::get<0>(m_queue.front());
221 T xiupp = std::get<1>(m_queue.front());
222 index_t level = std::get<2>(m_queue.front());
223 m_queue.pop_front();
224
225 T tlow = m_tmap[xilow];
226 T tupp = m_tmap[xiupp];
227
228 T dt;
229 if (xilow==xiupp && level==0)
230 dt = m_dt;
231 else
232 dt = (tupp-tlow);
233
234 GISMO_ASSERT(m_solutions.count(xilow)!=0,"Cannot find start point at tstart = "<<tlow<<"\n");
235 GISMO_ASSERT(m_prevs .count(xilow)!=0,"Cannot find previous solution for tstart = "<<tlow<<"\n");
236
237 solution_t start = *(m_solutions[xilow].get());
238
239 solution_t prev = *(m_prevs[xilow].get());
240
241 // add the job to the active jobs
242 m_jobs[m_ID++] = std::make_tuple(xilow,xiupp,level);
243 if (m_verbose==2) gsInfo<<"Got active job (ID="<<m_ID-1<<") on interval = ["<<xilow<<","<<xiupp<<"] = ["<<tlow<<","<<tupp<<"] with level "<<level<<"\n";
244
245 for (typename std::map<index_t,std::tuple<T,T,index_t>>::const_iterator it = m_jobs.begin(); it!=m_jobs.end(); it++)
246 {
247 std::tie(xilow,xiupp,level) = it->second;
248 gsDebug<<"job "<<it->first<<" on ["<<xilow<<","<<xiupp<<"] = ["<<tlow<<","<<tupp<<"] with level "<<level<<"\n";
249 }
250
251 return std::make_tuple(m_ID-1, dt, start, prev);
252}
253
254template <class T, class solution_t >
255bool gsAPALMData<T,solution_t>::getReferenceByTime(T time, solution_t & result)
256{
257 if (m_solutions.count(m_ximap[time])!=0)
258 {
259 result = *(m_solutions[m_ximap[time]].get());
260 return true;
261 }
262 else
263 return false;
264}
265
266template <class T, class solution_t >
267bool gsAPALMData<T,solution_t>::getReferenceByPar(T xi, solution_t & result)
268{
269 if (m_solutions.count(xi)!=0)
270 {
271 result = *(m_solutions[xi].get());
272 return true;
273 }
274 else
275 return false;
276}
277
278template <class T, class solution_t >
279bool gsAPALMData<T,solution_t>::getReferenceByID(index_t ID, solution_t & result)
280{
281 if (m_solutions.count(std::get<1>(m_jobs[ID]))!=0)
282 {
283 result = *(m_solutions[std::get<1>(m_jobs[ID])].get());
284 return true;
285 }
286 else
287 return false;
288}
289
290template <class T, class solution_t >
291void gsAPALMData<T,solution_t>::submit(index_t ID, const std::vector<T> & distances, std::vector<solution_t> solutions, const T & upperDistance, const T & lowerDistance)
292{
293 GISMO_ASSERT(m_initialized,"Structure is not initialized");
294 GISMO_ASSERT(distances.size()==solutions.size()+1,"You must provide one more distance than solutions");
295
296 // <d(xilow,xin) >
297 // <d(xilow,xi1)> <d(xi1,xi2) > <d(xi2,Dxin-1)> <d(xin-1,xin)> <d(xin,xiupp)>
298 // |--------------|-------------|..............|--------------|--------------|
299 // xilow xi1 xi2 xin-1 xin xiupp
300
301 // All distances d(.,.) are measured in the solution space (not the parametric space!).
302 // D(.,.) is the sum of intervals
303 // By the triangle inequality, d(xilow,xin)\leq D(xilow,xin)
304
305 // N: number of interior points
306 // Xi: [xilow,xi1,...,xiupp] (size N+2)
307 // distances: [d(xilow,xi1),d(xi1,xi2),...,d(xin-1,xin),d(xin,xiupp)] (size N+1)
308 // solutions: [u(xi1),...,u(xin)] (size N)
309 // lowerDistance = d(xilow,xin)
310 // upperDistance = d(xilow,xiupp)
311
313 // Rescale intervals
315 T tlow, tupp, xilow, xiupp, dxi, Dt, dt;
316 std::vector<T> t,xi;
317 index_t level;
318
319 // Compute interval (xi and t)
320 std::tie(xilow,xiupp,level) = m_jobs[ID];
321 tlow = m_tmap[xilow];
322 tupp = m_tmap[xiupp];
323
324 // Compute interval distance
325 dxi = xiupp - xilow;
326 // Get the original distance
327 Dt = tupp - tlow; // original time step
328
329 // Get time points
330 t.resize(distances.size()+1);
331 t.at(0) = tlow;
332 for (size_t k=0; k!=distances.size(); k++)
333 t.at(k+1) = t.at(k) + distances.at(k);
334
335 // check if the total distance matches the original time step
336 T dt_tmp = std::accumulate(distances.begin(), std::prev(distances.end()), 0.0);
337 GISMO_ENSURE((Dt-dt_tmp)/Dt<1e-12,"Total distance of the computed intervals should be equal to the original interval length ("<<dt_tmp<<"!="<<Dt<<")");
338
339 // get the total travelled distance
340 dt = t.back()-tlow;
341
342 // Compute the lower and upper errors
343 // The lowerError is the surplus distance over the first intervals
344 // The upperError is the distance between the last computed point and the referemce, minus the lowerError
345 T totalError = dt-upperDistance;
346 T lowerError = Dt-lowerDistance;
347 T upperError = totalError-lowerError;
348
349 // T lowerError = Dt-lowerDistance;
350 // T upperError = upperDistance-Dt;
351 // T totalError = upperError+lowerError;
352 // gsDebugVar(totalError);
353 // gsDebugVar(lowerError);
354 // gsDebugVar(upperError);
355
356 // Fill and scale xi vector
357 xi.resize(solutions.size()+2);
358 xi.front() = xilow;
359 xi.back() = xiupp;
360 for (size_t k=1; k!=xi.size()-1; k++)
361 xi.at(k) = xilow + dxi * ( t.at(k) - t.front() ) / dt;
362
363 // If the upper error is small enough, we don't store the solution
364 // Also in this case, the lower error is likely to be small as well
365
366 if (m_verbose==1)
367 {
368 gsInfo<<"Relative errors:\n";
369 gsInfo<<"\tlowerError/dt = "<<lowerError/dt<<"\n";
370 gsInfo<<"\tupperError/dt = "<<upperError/dt<<"\n";
371 }
372 // if (totalError/dt < m_tolerance)
373 if (false)
374 {
375 GISMO_ASSERT(lowerError/dt<m_tolerance,"Lower error is larger than total error. How is this possible?");
376 t .erase(t .end()-2);
377 xi.erase(xi.end()-2);
378 solutions.erase(solutions.end()-1);
379
380 // IS THIS CORRECT????
381 }
382 else
383 {
384 size_t kmin = 1;
385 size_t kmax = xi.size();
386 if (lowerError/Dt<m_tolerance)
387 kmin = xi.size()-1;
388 if (upperError/Dt<m_tolerance)
389 kmax = xi.size()-1;
390 for (size_t k = kmin; k!=kmax; k++)
391 {
392 if (level < m_maxLevel)
393 {
394 m_queue.push_back(std::make_tuple(xi.at(k-1),xi.at(k),level+1));
395 if (m_verbose==1) gsInfo<<"Interval ["<<xi.at(k-1)<<","<<xi.at(k)<<"] on level "<<level+1<<" added to queue\n";
396 }
397 else
398 {
399 if (m_verbose==1) gsInfo<<"Interval ["<<xi.at(k-1)<<","<<xi.at(k)<<"] on level "<<level+1<<" NOT added to queue (max level reached)\n";
400 }
401
402 }
403 }
404
406 // Push the data
408
409 // Transform the time vector
410 m_t.addConstant(tupp,dt-Dt);
411
412 for (size_t k=1; k!=t.size()-1; k++)
413 {
414 m_t.insert(t.at(k));
415 m_xi.insert(xi.at(k));
416 }
417
418 this->_buildMap();
419
420 for (size_t k=1; k!=xi.size()-1; k++) // add only INTERIOR solutions
421 {
422 if (m_verbose==2) gsInfo<<"Added a solution on time = "<<m_tmap[xi.at(k)]<<" (parametric time = "<<xi.at(k)<<")\n";
423 m_solutions[xi.at(k)] = std::make_shared<solution_t>(solutions.at(k-1));
424 m_levels[xi.at(k)] = level;
425 }
426
427 // The previous solution for the first computed point (xi[1]) is the solution on xi[0]
428 for (size_t k=1; k!=xi.size()-1; k++) // add only INTERIOR solutions
429 {
430 if (m_verbose==2) gsInfo<<"Added a previous solution on time = "<<m_tmap[xi.at(k)]<<" (parametric time = "<<xi.at(k)<<")\n";
431 m_prevs[xi.at(k)] = std::make_shared<solution_t>(*(m_solutions[xi.at(k-1)].get()));
432 }
433}
434
435template <class T, class solution_t >
436T gsAPALMData<T,solution_t>::jobStartTime(index_t ID)
437{
438 return m_tmap[std::get<0>(m_jobs[ID])];
439}
440
441template <class T, class solution_t >
442T gsAPALMData<T,solution_t>::jobStartPar(index_t ID)
443{
444 return std::get<0>(m_jobs[ID]);
445}
446
447template <class T, class solution_t >
448std::pair<T,T> gsAPALMData<T,solution_t>::jobTimes(index_t ID)
449{
450 T xilow,xiupp;
451 std::tie(xilow,xiupp,std::ignore) = m_jobs[ID];
452 return std::make_pair(m_tmap[xilow],m_tmap[xiupp]);
453
454}
455
456template <class T, class solution_t >
457std::pair<T,T> gsAPALMData<T,solution_t>::jobPars(index_t ID)
458{
459 T xilow,xiupp;
460 std::tie(xilow,xiupp,std::ignore) = m_jobs[ID];
461 return std::make_pair(xilow,xiupp);
462}
463
464template <class T, class solution_t >
465index_t gsAPALMData<T,solution_t>::jobLevel(index_t ID)
466{
467 return std::get<2>(m_jobs[ID]);
468}
469
470template <class T, class solution_t >
471void gsAPALMData<T,solution_t>::printActiveJobs()
472{
473 for (typename std::map<index_t,std::tuple<T,T,index_t>>::const_iterator it = m_jobs.cbegin(); it!= m_jobs.cend(); it++)
474 {
475 gsInfo<<"ID = "<<it->first<<": xilow = "<<std::get<0>(it->second)<<"; xiupp = "<<std::get<1>(it->second)<<"; level = "<<std::get<2>(it->second)<<"\n";
476 }
477}
478
479template <class T, class solution_t >
480void gsAPALMData<T,solution_t>::finishJob(index_t ID)
481{
482 // Remove ID
483 if (m_verbose==2) gsInfo<<"Erasing finished job on level = "<<std::get<0>(m_jobs[ID])
484 <<"; time = "<<std::get<1>(m_jobs[ID])<<"\n";
485 m_jobs.erase(ID);
486 if (m_verbose==2)
487 {
488 gsDebug<<"Current active jobs\n";
489 for (typename std::map<index_t,std::tuple<T,T,index_t>>::const_iterator it = m_jobs.begin(); it!=m_jobs.end(); ++it)
490 gsDebug<<"ID = "<<it->first<<"; xilow = "<<std::get<0>(it->second)<<"; xiupp = "<<std::get<1>(it->second)<<"; level = "<<std::get<2>(it->second)<<"\n";
491 }
492}
493
494template <class T, class solution_t >
495bool gsAPALMData<T,solution_t>::empty()
496{
497 return m_queue.empty();
498}
499
500template <class T, class solution_t >
501std::tuple<std::vector<T>,std::vector<solution_t>,std::vector<index_t>> gsAPALMData<T,solution_t>::getFlatSolution(index_t level)
502{
503 std::vector<T> times;
504 std::vector<solution_t> solutions;
505 std::vector<index_t> levels;
506
507 for (typename std::map<T,std::shared_ptr<solution_t>>::const_iterator
508 it = m_solutions.begin();
509 it!=m_solutions.end();
510 ++it)
511 {
512 if (m_levels[it->first]==level || level==-1)
513 {
514 times.push_back(m_tmap[it->first]);
515 solutions.push_back(*(it->second.get()));
516 levels.push_back(m_levels[it->first]);
517 }
518 }
519 return std::make_tuple(times,solutions,levels);
520}
521
522template <class T, class solution_t >
523void gsAPALMData<T,solution_t>::print()
524{
525 for (typename std::map<T,std::shared_ptr<solution_t>>::const_iterator
526 it = m_solutions.begin();
527 it!=m_solutions.end();
528 ++it)
529 {
530 gsInfo<<"\t";
531 gsInfo<<"time = "<<it->first<<"\n";
532 }
533}
534
535template <class T, class solution_t >
536void gsAPALMData<T,solution_t>::printQueue()
537{
538 std::deque<std::tuple<T,T,index_t>> queue = m_queue;
539 gsInfo<<"Queue has "<<queue.size()<<" elements\n";
540 while (!queue.empty())
541 {
542 gsInfo<<"Start time "<<std::get<0>(queue.front())
543 <<"; end time = "<<std::get<1>(queue.front())
544 <<"; level = "<<std::get<2>(queue.front())<<"\n";
545 queue.pop_front();
546 }
547 gsInfo<<"Queue is empty\n";
548}
549
550template <class T, class solution_t >
551void gsAPALMData<T,solution_t>::printKnots()
552{
553 gsInfo<<"xi = \n"<<m_xi.asMatrix()<<"\n";
554 gsInfo<<"t = \n"<<m_t.asMatrix()<<"\n";
555}
556
557template <class T, class solution_t >
558std::tuple<T,T,index_t> gsAPALMData<T,solution_t>::_activeJob(index_t ID)
559{
560 if (m_jobs.count(ID) == 1)
561 return m_jobs[ID];
562 else if (m_jobs.count(ID) > 1)
563 {
564 gsWarn<<"Multiple jobs with ID "<<ID<<" exist! Did something go wrong?\n";
565 return m_jobs[ID];
566 }
567 else
568 GISMO_ERROR("No job found with ID "<<ID<<". Did something go wrong?");
569}
570
571template <class T, class solution_t >
572void gsAPALMData<T,solution_t>::_buildMap()
573{
574 GISMO_ASSERT(m_xi.size()==m_t.size(),"Time and parametric time don't have equal length");
575 m_tmap.clear();
576 m_ximap.clear();
577 for (size_t k=0; k!=m_xi.size(); k++)
578 {
579 m_tmap.insert({m_xi[k],m_t[k]});
580 m_ximap.insert({m_t[k],m_xi[k]});
581 }
582}
583
584} // namespace gismo
#define index_t
Definition gsConfig.h:32
#define gsDebug
Definition gsDebug.h:61
#define GISMO_ERROR(message)
Definition gsDebug.h:118
#define gsWarn
Definition gsDebug.h:50
#define GISMO_ENSURE(cond, message)
Definition gsDebug.h:102
#define gsInfo
Definition gsDebug.h:43
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
The G+Smo namespace, containing all definitions for the library.