root/src/grid_GridAndTime_impl.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_vertexList
  2. get_relevant_precision
  3. identity_map
  4. get_relevant_precision
  5. create_precision_vec
  6. max
  7. node_to_string
  8. string_to_node
  9. normalize_node
  10. clean_whitespace
  11. dgfFile_to_vec
  12. to_string
  13. to_key

   1 /*! \file grid_GridAndTime_impl.cpp
   2     \brief Implementation of grid_GridAndTime_impl.h
   3 
   4      Revision history
   5      --------------------------------------------------
   6 
   7           Revised by Christian Power June 2016
   8           Originally written by Christian Power
   9                (power22c@gmail.com) 25. Februar 2016
  10 
  11     \author Christian Power
  12     \date 7. June 2016
  13     \copyright Copyright (c) 2016 Christian Power.  All rights reserved.
  14  */
  15 
  16 #include <iterator>
  17 #include <dassert.h>
  18 #include "grid_GridAndTime_impl.h"
  19 
  20 using namespace std;
  21 using Esfem::Impl::Evolving_grid;
  22 using Esfem::Impl::hash::grid;
  23 using Node = Evolving_grid::Node;
  24 using Nodes_key = Evolving_grid::Nodes_key;
  25 using Map = Evolving_grid::Map;
  26 
  27 
  28 // ----------------------------------------------------------------------
  29 // Evolving_grid
  30 
  31 Esfem::Impl::Evolving_grid::Evolving_grid(const std::string& filename)
  32 try : original_vertices {get_vertexList(filename)},
  33   digit_precision {get_relevant_precision(original_vertices)},
  34   vertices_map {identity_map(original_vertices, digit_precision)}
  35 {}
  36 catch(const std::exception&){
  37   std::throw_with_nested
  38     (logic_error {"Error in constructor of Evolving_grid."});
  39  }
  40  catch(...){
  41    throw logic_error {"Unknown error in constructor of Evolving_grid."};
  42  }
  43 
  44 const Node& Esfem::Impl::Evolving_grid::operator[](const Node& node) const try{
  45   const auto node_as_string = node_to_string(node, digit_precision);
  46   const Node* n_ptr {nullptr};
  47   try{ n_ptr = &vertices_map.at(node_as_string); }
  48   catch(...){
  49     throw runtime_error {"Bad input: " + node_as_string};
  50   }
  51   return *n_ptr;
  52  }
  53  catch(const std::exception&){
  54    std::throw_with_nested
  55      (runtime_error {"Error in Evolving_grid::operator[]."});
  56  }
  57  catch(...){
  58    throw runtime_error {"Unkown error in Evolving_grid::operator[]."};
  59  }
  60 
  61 Esfem::Impl::Evolving_grid& Esfem::Impl::Evolving_grid::
  62 operator=(const Grid::Vec_FEfun& new_nodes) try{
  63   using std::cbegin;
  64   using std::cend;
  65     
  66   constexpr std::size_t dim = 3;
  67   static_assert(dim == Node::dimension, "Bad dimension.");
  68   const auto no_vertices = original_vertices.size();  
  69   const auto dof_times_dim = new_nodes.size();
  70   if(no_vertices * dim != dof_times_dim) throw logic_error {"Bad dimension."};
  71   
  72   update_vertices(cbegin(new_nodes), cend(new_nodes), cbegin(original_vertices), dim);
  73  }
  74  catch(const std::exception&){
  75    std::throw_with_nested
  76      (runtime_error {"Error in Evolving_grid::operator=()."});
  77  }
  78  catch(...){
  79    throw runtime_error {"Unkown error in Evolving_grid::operator=()."};
  80  }
  81 
  82 // ----------------------------------------------------------------------
  83 // helper functions
  84 
  85 Nodes_key Esfem::Impl::
  86 get_vertexList(const std::string& filename) try{
  87   using std::cbegin;
  88   using std::cend;
  89   const auto whole_file = dgfFile_to_vec(filename);
  90 
  91   auto first = dgf_find_vertex(cbegin(whole_file), cend(whole_file), filename);
  92   auto last = dgf_close_list(first, cend(whole_file), filename);  
  93   return {first, last};
  94  }
  95  catch(const std::exception&){
  96    std::throw_with_nested
  97      (logic_error {"Error in get_vertexList()."});
  98  }
  99  catch(...){
 100    throw runtime_error {"Unknown error in get_vertexList()."};
 101  }
 102 size_t Esfem::Impl::
 103 get_relevant_precision(const vector<string>& vertex_list) try{
 104   if(vertex_list.empty()) throw logic_error {"Empty input"};
 105   const auto precision_vec = create_precision_vec(vertex_list);
 106   return Esfem::Impl::max(precision_vec);
 107  }
 108  catch(const std::exception&){
 109    std::throw_with_nested
 110      (runtime_error {"Error in get_relevant_precision(const vector<string>&)"});
 111  }
 112  catch(...){
 113    throw runtime_error
 114    {"Unknown error in get_relevant_precision(const vector<string>&)"};
 115  }
 116 
 117 Map Esfem::Impl::
 118 identity_map(const Nodes_key& nodes_lines, const std::size_t precision){
 119   Map rv {};
 120   rv.reserve(nodes_lines.size());
 121   for(const auto& line : nodes_lines)    
 122     rv[normalize_node(line, precision)] = string_to_node(line);
 123   return rv;
 124 }
 125 
 126 std::size_t Esfem::Impl::get_relevant_precision(const std::string& number) try{
 127   const auto dot_iter = number.find(".");
 128   const auto exp_iter = number.find("e");
 129   const auto dist = exp_iter - dot_iter ;
 130   if(dist < 1) throw logic_error {"Input has not scientific format."};
 131   return dist;
 132  }
 133  catch(const std::exception&){
 134    std::throw_with_nested(logic_error
 135                           {"Error in get_relevant_precision(const string&)"});
 136  }
 137  catch(...){
 138    throw runtime_error {"Unknown error in get_relevant_precision(const string&)"};
 139  }
 140 vector<size_t> Esfem::Impl::create_precision_vec(const vector<string>& vertex_list){
 141   vector<size_t> rv {};
 142   
 143   constexpr int world_dim {3};
 144   rv.reserve(vertex_list.size() * world_dim);
 145   // We assume that each line of vertex_list contains three numbers.
 146   
 147   for(const auto& line : vertex_list){
 148     istringstream interpreter {line};
 149     for(string s; interpreter >> s; )
 150       rv.push_back(get_relevant_precision(s));
 151   }
 152   return rv;
 153 }
 154 
 155 std::size_t Esfem::Impl::max(const std::vector<std::size_t>& v){
 156   const auto rv_ptr = max_element(cbegin(v), cend(v));
 157   if(rv_ptr == cend(v)) throw logic_error {"Error in max()"};
 158   return *rv_ptr;
 159 }
 160 
 161 std::string Esfem::Impl::node_to_string(const Node& node, const int precision) try{
 162   // assuming that the dgf file uses std::scientific as it should be.
 163   std::ostringstream oss;
 164   oss << std::scientific;
 165   for(std::size_t i = 0; i < Node::dimension - 1; ++i)
 166     if( !(oss << std::setprecision(precision) << node[i] << ' ') )
 167       throw runtime_error {"Node is too big."};
 168   oss << std::setprecision(precision) << node[Node::dimension - 1];
 169 
 170   // std::clog << "node_to_string()" << '\n'
 171   //        << "precision: " << precision << '\n'
 172   //        << "input: " << node[0] << ' ' << node[1] <<  ' ' << node[2] << std::endl;
 173   // std::clog <<  "output: " << oss.str() << std::endl;
 174   
 175   return oss.str();
 176  }
 177  catch(const std::exception&){
 178    std::throw_with_nested(runtime_error {"Error in node_to_string()."});
 179  }
 180  catch(...){
 181    throw runtime_error {"Unknown error in node_to_string()."};
 182  }
 183 
 184 Node Esfem::Impl::string_to_node(const std::string& str_node) try{
 185   std::istringstream interpreter {str_node};
 186   Node rv;
 187   double value {0.};
 188   for(std::size_t it = 0; it < Node::dimension; ++it){
 189     if(interpreter >> value) rv[it] = value;
 190     else throw runtime_error("operator>>() failed!");
 191   }
 192   if( !(interpreter >> std::ws).eof()) // stuff left in stream
 193     throw runtime_error("Stuff left in node.");
 194   return rv;
 195  }
 196  catch(const std::exception&){
 197    std::throw_with_nested
 198      (runtime_error {"Error in string_to_node()."});
 199  }
 200  catch(...){
 201    throw runtime_error {"Unknown error in string_to_node()."};
 202  }
 203 
 204 std::string Esfem::Impl::
 205 normalize_node(const std::string& str_node, const int precision){
 206   return node_to_string(string_to_node(str_node), precision);
 207 }
 208 
 209 std::string Esfem::Impl::clean_whitespace(const std::string& line){
 210   std::string clean_line {};
 211   std::istringstream iss {line};
 212   for(std::string s; iss >> s; )
 213     clean_line += s + ' ';
 214   clean_line.pop_back();        // delete last whitespace
 215   return clean_line;
 216 }
 217 
 218 std::vector<std::string> Esfem::Impl::
 219 dgfFile_to_vec(const std::string& filename) try{
 220   std::ifstream dgf_file {filename};
 221   if(!dgf_file) throw logic_error {"Could not open \"" + filename + "\"."};
 222   
 223   std::vector<std::string> lines;
 224   for(std::string line; std::getline(dgf_file, line); )
 225     lines.push_back(clean_whitespace(line));
 226   dgf_file.close();
 227   return lines;
 228  }
 229  catch(const std::exception&){
 230    std::throw_with_nested
 231      (runtime_error {"Error in dgfFile_to_vec()."});
 232  }
 233  catch(...){
 234    throw runtime_error {"Unknown error in dgfFile_to_vec()."};
 235  }
 236 
 237 // ----------------------------------------------------------------------
 238 // hash_grid
 239 
 240 grid::grid(const std::string& fname){
 241   const auto str_keys = get_vertexList(fname);
 242 
 243   m.reserve(str_keys.size());
 244   ol.reserve(str_keys.size());
 245   istringstream iss;
 246   iss.exceptions(ios_base::badbit);
 247   size_t line_no {1};
 248   range k {};
 249   try{
 250     for(const auto& line : str_keys){
 251       iss.str(line);
 252       for(int i = 0; i < dim; ++i) if(!(iss >> k[i])) throw bad {"Non-number"}; 
 253       if(!(iss >> ws).eof()) throw bad {"Too many entries."};
 254       const auto k2 = to_key(k);
 255       m.emplace(k2, k);
 256       ol.emplace_back(k2);
 257       iss.clear();
 258       ++line_no;
 259     }
 260   }
 261   catch(...){
 262     ostringstream oss;
 263     oss << "In " << fname << " vertex no. " << line_no << ": "
 264         << str_keys[line_no-1];
 265     throw_with_nested(bad {Assert::compose(__FILE__, __LINE__, oss.str())});
 266   }
 267 }
 268 grid::grid(const Grid::Vec_FEfun& init_keys){
 269   const auto size = init_keys.size()/dim;
 270 
 271   Assert::dynamic<Assert::level(Assert::default_level), bad>
 272     (size * dim == init_keys.size(),
 273      Assert::compose(__FILE__, __LINE__, "init_keys.size()%dim != 0"));
 274 
 275   m.reserve(size);
 276   ol.reserve(size);
 277   for(auto it = init_keys.begin(); it != init_keys.end(); ++it){
 278     range k {};
 279     for(int i = 0; i < dim; ++i, ++it) k[i] = *it;
 280     const auto k2 = to_key(k);
 281     m.emplace(k2, k);
 282     ol.emplace_back(k2);
 283   }
 284 }
 285 
 286 auto grid::operator=(const Grid::Vec_FEfun& value_list) -> grid&{
 287   Assert::dynamic<Assert::level(Assert::default_level), bad>
 288     (dim * m.size() == value_list.size(),
 289      Assert::compose(__FILE__, __LINE__, "grid::operator=()"));
 290 
 291   auto m_it = ol.cbegin();
 292   range k {};  
 293   for(auto v_it = value_list.begin(); v_it != value_list.end(); ){
 294     for(int i = 0; i < dim; ++i, ++v_it) k[i] = *v_it;
 295     m.at(*m_it++) = k;
 296   }
 297   return *this;
 298 }
 299 auto grid::operator[](const range& k) const -> const range& try{
 300   return m.at(to_key(k));
 301  }
 302  catch(...){
 303    throw_with_nested(bad {to_string(k)});
 304  }
 305 std::string Esfem::Impl::hash::to_string(const range& k){
 306   ostringstream oss;
 307   oss << scientific << '('
 308       << setprecision(17) << k[0] << ", "
 309       << setprecision(17) << k[1] << ", "
 310       << setprecision(17) << k[2] << ')';
 311   return oss.str();
 312 }
 313 auto Esfem::Impl::hash::to_key(const range& r) -> key{
 314   constexpr auto fac = 1e5;
 315   key rv {};
 316   for(int i = 0; i < range::dimension; ++i)
 317     rv[i] = static_cast<int>(fac * r[i]);
 318   return rv;
 319 }

/* [<][>][^][v][top][bottom][index][help] */