G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsAPALMData.hpp
Go to the documentation of this file.
1 
14 #pragma once
15 
16 namespace gismo
17 {
18 
19 template <class T, class solution_t >
20 gsAPALMData<T,solution_t>::gsAPALMData( const std::vector<T> & times,
21  const std::vector<solution_t> & solutions)
22 :
23 m_initialized(false),
24 m_dt(1.0)
25 {
26  GISMO_ASSERT(times.size()==solutions.size(),"Sizes must agree");
27 
28  setData(times,solutions);
29 
30  _defaultOptions();
31 }
32 
33 template <class T, class solution_t >
34 gsAPALMData<T,solution_t>::gsAPALMData(const std::vector<T> & times)
35 :
36 m_initialized(false),
37 m_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 
47 template <class T, class solution_t >
48 gsAPALMData<T,solution_t>::gsAPALMData()
49 :
50 m_initialized(false),
51 m_dt(1.0)
52 {
53  _defaultOptions();
54  m_t = gsKnotVector<T>(0);
55 }
56 
57 template <class T, class solution_t >
58 void 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 
68 template <class T, class solution_t >
69 void 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 
77 template <class T, class solution_t >
78 void 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 
99 template <class T, class solution_t >
100 void 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 
124 template <class T, class solution_t >
125 void 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 
135 template <class T, class solution_t >
136 void 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 
177 template <class T, class solution_t >
178 void 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 
207 template <class T, class solution_t >
208 void 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 
214 template <class T, class solution_t >
215 std::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 
254 template <class T, class solution_t >
255 bool 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 
266 template <class T, class solution_t >
267 bool 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 
278 template <class T, class solution_t >
279 bool 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 
290 template <class T, class solution_t >
291 void 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 
435 template <class T, class solution_t >
436 T gsAPALMData<T,solution_t>::jobStartTime(index_t ID)
437 {
438  return m_tmap[std::get<0>(m_jobs[ID])];
439 }
440 
441 template <class T, class solution_t >
442 T gsAPALMData<T,solution_t>::jobStartPar(index_t ID)
443 {
444  return std::get<0>(m_jobs[ID]);
445 }
446 
447 template <class T, class solution_t >
448 std::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 
456 template <class T, class solution_t >
457 std::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 
464 template <class T, class solution_t >
465 index_t gsAPALMData<T,solution_t>::jobLevel(index_t ID)
466 {
467  return std::get<2>(m_jobs[ID]);
468 }
469 
470 template <class T, class solution_t >
471 void 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 
479 template <class T, class solution_t >
480 void 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 
494 template <class T, class solution_t >
495 bool gsAPALMData<T,solution_t>::empty()
496 {
497  return m_queue.empty();
498 }
499 
500 template <class T, class solution_t >
501 std::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 
522 template <class T, class solution_t >
523 void 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 
535 template <class T, class solution_t >
536 void 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 
550 template <class T, class solution_t >
551 void gsAPALMData<T,solution_t>::printKnots()
552 {
553  gsInfo<<"xi = \n"<<m_xi.asMatrix()<<"\n";
554  gsInfo<<"t = \n"<<m_t.asMatrix()<<"\n";
555 }
556 
557 template <class T, class solution_t >
558 std::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 
571 template <class T, class solution_t >
572 void 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 gsDebug
Definition: gsDebug.h:61
#define index_t
Definition: gsConfig.h:32
#define GISMO_ENSURE(cond, message)
Definition: gsDebug.h:102
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
#define gsWarn
Definition: gsDebug.h:50
#define gsInfo
Definition: gsDebug.h:43
#define GISMO_ERROR(message)
Definition: gsDebug.h:118