RINGMesh  Version 5.0.0
A programming library for geological model meshes
io_gm.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012-2017, Association Scientifique pour la Geologie et ses
3  * Applications (ASGA). All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of ASGA nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ASGA BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * http://www.ring-team.org
28  *
29  * RING Project
30  * Ecole Nationale Superieure de Geologie - GeoRessources
31  * 2 Rue du Doyen Marcel Roubault - TSA 70605
32  * 54518 VANDOEUVRE-LES-NANCY
33  * FRANCE
34  */
35 
36 namespace {
37  using namespace RINGMesh;
38 
39  template< index_t > class GeoModelBuilderGM;
40 
41  bool match_mesh_entity_type( const MeshEntityType& type )
42  {
43  if( type == Corner3D::type_name_static() ) return true;
44  if( type == Line3D::type_name_static() ) return true;
45  if( type == Surface3D::type_name_static() ) return true;
46  if( type == Region3D::type_name_static() ) return true;
47  return false;
48  }
49 
50  template< index_t DIMENSION >
51  class GeoModelBuilderGMImpl {
52  public:
53  GeoModelBuilderGMImpl(
54  GeoModelBuilderGM< DIMENSION >& builder,
55  GeoModel< DIMENSION >& geomodel )
56  : builder_( builder ), geomodel_( geomodel )
57  {
58  }
59  virtual ~GeoModelBuilderGMImpl() = default;
60 
61  virtual void read_mesh_entity_line( GEO::LineInput& file_line ) = 0;
62 
63  protected:
64  GeoModelBuilderGM< DIMENSION >& builder_;
65  GeoModel< DIMENSION >& geomodel_;
66  };
67 
68  template< index_t DIMENSION >
69  class GeoModelBuilderGMImpl_0: public GeoModelBuilderGMImpl< DIMENSION > {
70  public:
71  GeoModelBuilderGMImpl_0(
72  GeoModelBuilderGM< DIMENSION >& builder,
73  GeoModel< DIMENSION >& geomodel )
74  : GeoModelBuilderGMImpl< DIMENSION >( builder, geomodel )
75  {
76  }
77  virtual ~GeoModelBuilderGMImpl_0() = default;
78 
79  void read_mesh_entity_line( GEO::LineInput& file_line ) override
80  {
81  // First line : type - id - name - geol_feature
82  if( file_line.nb_fields() < 4 ) {
83  throw RINGMeshException( "I/O", "Invalid line: ",
84  file_line.line_number(),
85  ", 4 fields are expected, the type, id, name, and geological feature" );
86  }
87  auto entity = read_first_line( file_line );
88  read_second_line( file_line, entity );
89  }
90 
91  protected:
92  virtual gmme_id read_first_line( GEO::LineInput& file_line )
93  {
94  gmme_id cur_gmme { MeshEntityType { file_line.field( 0 ) },
95  file_line.field_as_uint( 1 ) };
96  this->builder_.info.set_mesh_entity_name( cur_gmme,
97  file_line.field( 2 ) );
98  return cur_gmme;
99  }
100  void read_second_line( GEO::LineInput& file_line, const gmme_id& entity );
101  private:
102  template< template< index_t > class ENTITY >
103  void add_relation_for_entities_with_sides(
104  const gmme_id& entity,
105  GEO::LineInput& file_line )
106  {
107  for( auto c : range( file_line.nb_fields() ) ) {
108  bool side { false };
109  if( std::strncmp( file_line.field( c ), "+", 1 ) == 0 ) {
110  side = true;
111  }
112  index_t s { NO_ID };
113  GEO::String::from_string( &file_line.field( c )[1], s );
114 
115  this->builder_.topology.add_mesh_entity_boundary_relation( entity, {
116  ENTITY< DIMENSION >::type_name_static(), s }, side );
117  }
118  }
119 
120  void add_relation_for_entities_with_no_side(
121  const gmme_id& entity,
122  GEO::LineInput& file_line )
123  {
124  const auto& manager =
125  this->geomodel_.entity_type_manager().mesh_entity_manager;
126  auto type = manager.boundary_entity_type( entity.type() );
127  // Second line : indices of boundaries
128  for( auto c : range( 1, file_line.nb_fields() ) ) {
129  gmme_id boundary { type, file_line.field_as_uint( c ) };
130  this->builder_.topology.add_mesh_entity_boundary_relation( entity,
131  boundary );
132  }
133  }
134  };
135 
136  template< >
137  void GeoModelBuilderGMImpl_0< 2 >::read_second_line(
138  GEO::LineInput& file_line,
139  const gmme_id& entity )
140  {
141  file_line.get_line();
142  file_line.get_fields();
143  const auto& manager =
144  this->geomodel_.entity_type_manager().mesh_entity_manager;
145  if( manager.is_surface( entity.type() ) ) {
146  add_relation_for_entities_with_sides< Line >( entity, file_line );
147  } else {
148  add_relation_for_entities_with_no_side( entity, file_line );
149  }
150  }
151 
152  template< >
153  void GeoModelBuilderGMImpl_0< 3 >::read_second_line(
154  GEO::LineInput& file_line,
155  const gmme_id& entity )
156  {
157  file_line.get_line();
158  file_line.get_fields();
159  const auto& manager =
160  this->geomodel_.entity_type_manager().mesh_entity_manager;
161  if( manager.is_region( entity.type() ) ) {
162  add_relation_for_entities_with_sides< Surface >( entity, file_line );
163  } else {
164  add_relation_for_entities_with_no_side( entity, file_line );
165  }
166  }
167 
168  template< index_t DIMENSION >
169  class GeoModelBuilderGMImpl_1: public GeoModelBuilderGMImpl_0< DIMENSION > {
170  public:
171  GeoModelBuilderGMImpl_1(
172  GeoModelBuilderGM< DIMENSION >& builder,
173  GeoModel< DIMENSION >& geomodel )
174  : GeoModelBuilderGMImpl_0< DIMENSION >( builder, geomodel )
175  {
176  }
177  virtual ~GeoModelBuilderGMImpl_1() = default;
178 
179  void read_mesh_entity_line( GEO::LineInput& file_line ) override
180  {
181  // Read this entity
182  // First line : type - id - name - geol_feature - mesh type
183  if( file_line.nb_fields() < 5 ) {
184  throw RINGMeshException( "I/O", "Invalid line: ",
185  file_line.line_number(),
186  ", 5 fields are expected, the type, id, name, ",
187  "geological feature, and mesh type" );
188  }
189  auto entity = this->read_first_line( file_line );
190 
191  const auto mesh_type = file_line.field( 4 );
192  if( GEO::String::string_starts_with( mesh_type, "Geogram" ) ) {
193  this->builder_.geometry.change_mesh_data_structure( entity,
194  old_2_new_name( mesh_type ) );
195  } else {
196  this->builder_.geometry.change_mesh_data_structure( entity,
197  mesh_type );
198  }
199 
200  this->read_second_line( file_line, entity );
201  }
202  private:
203  const std::string& old_2_new_name( const std::string& old_name )
204  {
205  auto new_name_pos = GEO::String::to_uint(
206  GEO::String::to_string( old_name.at( old_name.length() - 2 ) ) );
207  return new_names[new_name_pos];
208  }
209  private:
210  static const std::string new_names[4];
211  };
212 
213  template< index_t DIMENSION >
214  const std::string GeoModelBuilderGMImpl_1< DIMENSION >::new_names[4] = {
215  std::string( "GeogramPointSetMesh" ), std::string( "GeogramLineMesh" ),
216  std::string( "GeogramSurfaceMesh" ), std::string( "GeogramVolumeMesh" ) };
217 
218  template< index_t DIMENSION >
219  class GeoModelBuilderGMImpl_2: public GeoModelBuilderGMImpl_1< DIMENSION > {
220  public:
221  GeoModelBuilderGMImpl_2(
222  GeoModelBuilderGM< DIMENSION >& builder,
223  GeoModel< DIMENSION >& geomodel )
224  : GeoModelBuilderGMImpl_1< DIMENSION >( builder, geomodel )
225  {
226  }
227  virtual ~GeoModelBuilderGMImpl_2() = default;
228 
229  void read_mesh_entity_line( GEO::LineInput& file_line ) override
230  {
231  // Read this entity
232  // First line : type - id - name - mesh type
233  if( file_line.nb_fields() < 4 ) {
234  throw RINGMeshException( "I/O", "Invalid line: ",
235  file_line.line_number(),
236  ", 4 fields are expected, the type, id, name, ",
237  "geological feature, and mesh type" );
238  }
239  auto entity = this->read_first_line( file_line );
240 
241  const auto mesh_type = file_line.field( 3 );
242  this->builder_.geometry.change_mesh_data_structure( entity, mesh_type );
243 
244  this->read_second_line( file_line, entity );
245  }
246  };
247 
248  template< index_t DIMENSION >
249  class GeoModelBuilderGM final : public GeoModelBuilderFile< DIMENSION > {
250  public:
251  static const index_t NB_VERSION = 3;
252  GeoModelBuilderGM( GeoModel< DIMENSION >& geomodel, std::string filename )
253  : GeoModelBuilderFile< DIMENSION >( geomodel, std::move( filename ) )
254  {
255  version_impl_[0].reset(
256  new GeoModelBuilderGMImpl_0< DIMENSION >( *this, geomodel ) );
257  version_impl_[1].reset(
258  new GeoModelBuilderGMImpl_1< DIMENSION >( *this, geomodel ) );
259  version_impl_[2].reset(
260  new GeoModelBuilderGMImpl_2< DIMENSION >( *this, geomodel ) );
261  }
262  virtual ~GeoModelBuilderGM() = default;
263 
264  private:
265  void load_geological_entities( const std::string& geological_entity_file )
266  {
267  GEO::LineInput file_line { geological_entity_file };
268  while( !file_line.eof() && file_line.get_line() ) {
269  file_line.get_fields();
270  if( file_line.nb_fields() > 0 ) {
271  // If there is no geological entity
272  if( file_line.field_matches( 0, "No" )
273  && file_line.field_matches( 1, "geological" )
274  && file_line.field_matches( 2, "entity" ) ) {
275  return;
276  }
277  // Number of entities of a given type
278  if( file_line.field_matches( 0, "Nb" ) ) {
279  // Allocate the space
280  this->geology.create_geological_entities(
281  GeologicalEntityType( file_line.field( 1 ) ),
282  file_line.field_as_uint( 2 ) );
283  } else {
284  GeologicalEntityType type { file_line.field( 0 ) };
285  auto id = file_line.field_as_uint( 1 );
286  gmge_id entity { type, id };
287  this->info.set_geological_entity_name( entity,
288  file_line.field( 2 ) );
289  this->geology.set_geological_entity_geol_feature( entity,
291  file_line.field( 3 ) ) );
292  file_line.get_line();
293  file_line.get_fields();
294  for( auto in_b : range( file_line.nb_fields() ) ) {
295  this->geology.add_parent_children_relation( entity,
296  { this->geomodel_.entity_type_manager().relationship_manager.child_type(
297  type ),
298  file_line.field_as_uint( in_b ) } );
299  }
300  }
301  }
302  }
303  }
304 
309  void load_meshes( UnZipFile& uz )
310  {
311  uz.start_extract();
312 
313  Logger::instance()->set_minimal( true );
314  std::vector< std::future< void > > files;
315  do {
316  auto file_name = uz.get_current_filename();
317  if( GEO::FileSystem::extension( file_name ) == "txt" ) {
318  continue;
319  }
320 
321  uz.get_current_file();
322  files.push_back(
323  std::async( std::launch::deferred,
324  [file_name, this] {
325  auto file_without_extension = GEO::FileSystem::base_name(
326  file_name );
327  std::string entity_type, entity_id;
328  GEO::String::split_string( file_without_extension, '_', entity_type,
329  entity_id );
330  index_t id { NO_ID };
331  GEO::String::from_string( entity_id, id );
332  load_mesh_entity( MeshEntityType {entity_type}, file_name, id );
333  GEO::FileSystem::delete_file( file_name );
334  } ) );
335  } while( uz.next_file() );
336 
337  for( auto& file : files ) {
338  file.get();
339  }
340  Logger::instance()->set_minimal( false );
341  }
342 
343  void load_mesh_entity(
344  const MeshEntityType& entity_type,
345  const std::string& file_name,
346  index_t id );
347 
348  bool load_mesh_entity_base(
349  const MeshEntityType& entity_type,
350  const std::string& file_name,
351  index_t id )
352  {
353  const auto& manager =
354  this->geomodel_.entity_type_manager().mesh_entity_manager;
355  if( manager.is_corner( entity_type ) ) {
356  auto builder = this->geometry.create_corner_builder( id );
357  builder->load_mesh( file_name );
358  return true;
359  } else if( manager.is_line( entity_type ) ) {
360  auto builder = this->geometry.create_line_builder( id );
361  builder->load_mesh( file_name );
362  return true;
363  } else if( manager.is_surface( entity_type ) ) {
364  auto builder = this->geometry.create_surface_builder( id );
365  builder->load_mesh( file_name );
366  return true;
367  }
368  return false;
369  }
370 
371  void load_file() final
372  {
373  UnZipFile uz { this->filename_ };
374 
375  const std::string mesh_entity_file( "mesh_entities.txt" );
376  uz.get_file( mesh_entity_file );
377  load_mesh_entities( mesh_entity_file );
378  auto ok = GEO::FileSystem::delete_file( mesh_entity_file );
379  ringmesh_unused( ok ); // avoids warning in release
380  ringmesh_assert( ok );
381  load_meshes( uz );
382 
383  const std::string geological_entity_file { "geological_entities.txt" };
384  uz.get_file( geological_entity_file );
385  load_geological_entities( geological_entity_file );
386  ok = GEO::FileSystem::delete_file( geological_entity_file );
387  ringmesh_assert( ok );
388  }
389 
390  void load_mesh_entities( const std::string& mesh_entity_file )
391  {
392  GEO::LineInput file_line { mesh_entity_file };
393  while( !file_line.eof() && file_line.get_line() ) {
394 
395  file_line.get_fields();
396  if( file_line.nb_fields() > 0 ) {
397  if( file_line.field_matches( 0, "Version" ) ) {
398  file_version_ = file_line.field_as_uint( 1 );
399  }
400  // Name of the geomodel
401  else if( file_line.field_matches( 0, "GeoModel" ) ) {
402  if( file_line.nb_fields() > 2 ) {
403  this->info.set_geomodel_name( file_line.field( 2 ) );
404  }
405  }
406  // Number of entities of a given type
407  else if( file_line.field_matches( 0, "Nb" ) ) {
408  // Allocate the space
409  this->topology.create_mesh_entities(
410  MeshEntityType( file_line.field( 1 ) ),
411  file_line.field_as_uint( 2 ) );
412  }
413  // Mesh entities
414  else if( match_mesh_entity_type(
415  MeshEntityType( file_line.field( 0 ) ) ) ) {
416  version_impl_[file_version_]->read_mesh_entity_line(
417  file_line );
418  }
419  }
420  }
421  }
422 
423  void load_region_if_entity_is_region(
424  const std::string& entity_type,
425  index_t id,
426  const std::string& file_name,
427  const MeshEntityTypeManager< DIMENSION >& manager );
428  private:
429  index_t file_version_ { 0 };
430  std::unique_ptr< GeoModelBuilderGMImpl< DIMENSION > > version_impl_[NB_VERSION];
431  };
432 
433  template< >
434  void GeoModelBuilderGM< 2 >::load_mesh_entity(
435  const MeshEntityType& entity_type,
436  const std::string& file_name,
437  index_t id )
438  {
439  load_mesh_entity_base( entity_type, file_name, id );
440  }
441 
442  template< >
443  void GeoModelBuilderGM< 3 >::load_mesh_entity(
444  const MeshEntityType& entity_type,
445  const std::string& file_name,
446  index_t id )
447  {
448  if( !load_mesh_entity_base( entity_type, file_name, id ) ) {
449  const auto& manager =
450  this->geomodel_.entity_type_manager().mesh_entity_manager;
451  if( manager.is_region( entity_type ) ) {
452  auto builder = geometry.create_region_builder( id );
453  builder->load_mesh( file_name );
454  }
455  }
456  }
457 
461  template< index_t DIMENSION >
462  void save_geological_entity(
463  std::ofstream& out,
465  {
467  out << E.gmge() << " " << E.name() << " ";
468  out
470  E.geological_feature() ) << EOL;
471 
473  for( auto j : range( E.nb_children() ) ) {
474  out << E.child_gmme( j ).index() << " ";
475  }
476  out << EOL;
477  }
478 
484  template< index_t DIMENSION >
485  void save_geological_entities(
486  const GeoModel< DIMENSION >& geomodel,
487  const std::string& file_name )
488  {
489  std::ofstream out { file_name.c_str() };
490  out.precision( 16 );
491  if( out.bad() ) {
492  throw RINGMeshException( "I/O", "Error when opening the file: ",
493  file_name );
494  }
495 
496  if( geomodel.nb_geological_entity_types() == 0 ) {
497  // Compression of an empty files crashes ? (in debug on windows at least)
498  out << "No geological entity in the geomodel" << EOL;
499  return;
500  }
501  for( auto i : range( geomodel.nb_geological_entity_types() ) ) {
502  const auto& type = geomodel.geological_entity_type( i );
503  auto nb = geomodel.nb_geological_entities( type );
504  out << "Nb " << type << " " << nb << EOL;
505  }
506  for( auto i : range( geomodel.nb_geological_entity_types() ) ) {
507  const auto& type = geomodel.geological_entity_type( i );
508  auto nb = geomodel.nb_geological_entities( type );
509  for( auto j : range( nb ) ) {
510  save_geological_entity( out, geomodel.geological_entity( type, j ) );
511  }
512  }
513  out << std::flush;
514  }
515 
516  template< typename ENTITY, index_t DIMENSION >
517  void save_mesh_entities_of_type(
518  const GeoModel< DIMENSION >& geomodel,
519  std::ofstream& out )
520  {
521  const MeshEntityType& type = ENTITY::type_name_static();
522  for( auto e : range( geomodel.nb_mesh_entities( type ) ) ) {
523  const ENTITY& cur_mesh_entity =
524  dynamic_cast< const ENTITY& >( geomodel.mesh_entity( type, e ) );
525  out << type << " " << e << " " << cur_mesh_entity.name() << " "
526  << cur_mesh_entity.mesh().type_name() << EOL;
527  out << "boundary ";
528  for( auto b : range( cur_mesh_entity.nb_boundaries() ) ) {
529  out << cur_mesh_entity.boundary_gmme( b ).index() << " ";
530  }
531  out << EOL;
532  }
533  }
534 
535  void save_dimension( index_t dimension, std::ofstream& out )
536  {
537  out << "Dimension " << dimension << EOL;
538  }
539 
540  template< index_t DIMENSION >
541  void save_version_and_name(
542  const GeoModel< DIMENSION >& geomodel,
543  std::ofstream& out )
544  {
545  out << "Version 2" << EOL;
546  out << "GeoModel name " << geomodel.name() << EOL;
547  }
548 
549  template< index_t DIMENSION >
550  void save_number_of_mesh_entities_base(
551  const GeoModel< DIMENSION >& geomodel,
552  std::ofstream& out )
553  {
554  // Numbers of the different types of mesh entities
555  out << "Nb " << Corner< DIMENSION >::type_name_static() << " "
556  << geomodel.nb_corners() << EOL;
557  out << "Nb " << Line< DIMENSION >::type_name_static() << " "
558  << geomodel.nb_lines() << EOL;
559  out << "Nb " << Surface< DIMENSION >::type_name_static() << " "
560  << geomodel.nb_surfaces() << EOL;
561  }
562 
563  template< index_t DIMENSION >
564  void save_number_of_mesh_entities(
565  const GeoModel< DIMENSION >& M,
566  std::ofstream& out );
567 
568  template< >
569  void save_number_of_mesh_entities(
570  const GeoModel2D& geomodel,
571  std::ofstream& out )
572  {
573  save_number_of_mesh_entities_base( geomodel, out );
574  }
575 
576  template< >
577  void save_number_of_mesh_entities(
578  const GeoModel3D& geomodel,
579  std::ofstream& out )
580  {
581  save_number_of_mesh_entities_base( geomodel, out );
582  out << "Nb " << Region < 3
583  > ::type_name_static() << " " << geomodel.nb_regions() << EOL;
584  }
585 
586  template< index_t DIMENSION >
587  void save_mesh_entities_topology_and_sides(
588  const GeoModel< DIMENSION >& geomodel,
589  std::ofstream& out );
590 
591  template< template< index_t > class ENTITY, index_t DIMENSION >
592  void save_mesh_entities_topology_and_sides_impl(
593  const GeoModel< DIMENSION >& geomodel,
594  std::ofstream& out )
595  {
596  for( auto i : range(
597  geomodel.nb_mesh_entities( ENTITY< DIMENSION >::type_name_static() ) ) ) {
598  const ENTITY< DIMENSION >& E =
599  static_cast< const ENTITY< DIMENSION >& >( geomodel.mesh_entity(
600  ENTITY< DIMENSION >::type_name_static(), i ) );
601  // Save ID - NAME
602  out << E.gmme() << " " << E.name() << " " << E.mesh().type_name() << EOL;
603  // Second line Signed ids of boundary surfaces
604  for( auto j : range( E.nb_boundaries() ) ) {
605  if( E.side( j ) ) {
606  out << "+";
607  } else {
608  out << "-";
609  }
610  out << E.boundary_gmme( j ).index() << " ";
611  }
612  out << EOL;
613  }
614  }
615 
616  template< >
617  void save_mesh_entities_topology_and_sides(
618  const GeoModel2D& geomodel,
619  std::ofstream& out )
620  {
621  save_mesh_entities_topology_and_sides_impl< Surface >( geomodel, out );
622  }
623 
624  template< >
625  void save_mesh_entities_topology_and_sides(
626  const GeoModel3D& geomodel,
627  std::ofstream& out )
628  {
629  save_mesh_entities_topology_and_sides_impl< Region >( geomodel, out );
630 
631  }
632 
633  template< index_t DIMENSION >
634  void save_mesh_entities_topology_base(
635  const GeoModel< DIMENSION >& geomodel,
636  std::ofstream& out )
637  {
638  save_mesh_entities_of_type< Corner< DIMENSION > >( geomodel, out );
639  save_mesh_entities_of_type< Line< DIMENSION > >( geomodel, out );
640  }
641 
642  template< index_t DIMENSION >
643  void save_mesh_entities_topology(
644  const GeoModel< DIMENSION >& geomodel,
645  std::ofstream& out );
646 
647  template< >
648  void save_mesh_entities_topology(
649  const GeoModel2D& geomodel,
650  std::ofstream& out )
651  {
652  save_mesh_entities_topology_base( geomodel, out );
653 
654  }
655  template< >
656  void save_mesh_entities_topology(
657  const GeoModel3D& geomodel,
658  std::ofstream& out )
659  {
660  save_mesh_entities_topology_base( geomodel, out );
661  save_mesh_entities_of_type< Surface3D >( geomodel, out );
662  }
663 
669  template< index_t DIMENSION >
670  void save_mesh_entities(
671  const GeoModel< DIMENSION >& geomodel,
672  const std::string& file_name )
673  {
674  std::ofstream out( file_name.c_str() );
675  out.precision( 16 );
676  if( out.bad() ) {
677  throw RINGMeshException( "I/O", "Error when opening the file: ",
678  file_name );
679  }
680  save_dimension( DIMENSION, out );
681  save_version_and_name( geomodel, out );
682  save_number_of_mesh_entities( geomodel, out );
683  save_mesh_entities_topology( geomodel, out );
684  save_mesh_entities_topology_and_sides( geomodel, out );
685  out << std::flush;
686  }
687 
688  template< index_t DIMENSION >
689  bool save_mesh(
690  const GeoModelMeshEntity< DIMENSION >& geomodel_entity_mesh,
691  const std::string& name );
692 
693  template< >
694  bool save_mesh(
695  const GeoModelMeshEntity3D& geomodel_entity_mesh,
696  const std::string& name )
697  {
698  if( geomodel_entity_mesh.type_name() == Region3D::type_name_static() ) {
699  const auto& region = geomodel_entity_mesh.geomodel().region(
700  geomodel_entity_mesh.index() );
701  if( !region.is_meshed() ) {
702  // a region is not necessary meshed.
703  return false;
704  }
705  }
706  geomodel_entity_mesh.save( name );
707  return true;
708  }
709 
710  template< >
711  bool save_mesh(
712  const GeoModelMeshEntity2D& geomodel_entity_mesh,
713  const std::string& name )
714  {
715  if( geomodel_entity_mesh.type_name() == Surface2D::type_name_static() ) {
716  const auto& surface = geomodel_entity_mesh.geomodel().surface(
717  geomodel_entity_mesh.index() );
718  if( !surface.is_meshed() ) {
719  return false;
720  }
721  }
722  geomodel_entity_mesh.save( name );
723  return true;
724  }
725 
726  template< typename ENTITY >
727  std::string build_string_for_geomodel_entity_export( const ENTITY& entity )
728  {
729  const auto& id = entity.gmme();
730  std::string base_name = id.type().string() + "_"
731  + std::to_string( id.index() );
732  return base_name + "." + entity.mesh().default_extension();
733  }
734 
740  template< typename ENTITY >
741  void save_geomodel_mesh_entity(
742  const ENTITY& geomodel_entity_mesh,
743  std::vector< std::string >& filenames )
744  {
745  static std::mutex lock;
746  auto name = build_string_for_geomodel_entity_export( geomodel_entity_mesh );
747  if( save_mesh( geomodel_entity_mesh, name ) ) {
748  std::lock_guard< std::mutex > locking( lock );
749  filenames.push_back( name );
750  }
751  }
752 
753  void zip_files( const std::vector< std::string >& filenames, ZipFile& zf )
754  {
755  for( const std::string& name : filenames ) {
756  zf.add_file( name );
757  GEO::FileSystem::delete_file( name );
758  }
759  }
760 
761  template< template< index_t > class ENTITY, index_t DIMENSION >
762  void save_geomodel_mesh_entities(
763  const GeoModel< DIMENSION >& geomodel,
764  std::vector< std::string >& filenames )
765  {
766  const auto& type = ENTITY< DIMENSION >::type_name_static();
767  auto* logger = Logger::instance();
768  auto logger_status = logger->is_quiet();
769  logger->set_quiet( true );
770  parallel_for( geomodel.nb_mesh_entities( type ),
771  [&geomodel, &type, &filenames]( index_t i ) {
772  const auto& entity =
773  dynamic_cast< const ENTITY< DIMENSION >& >( geomodel.mesh_entity(
774  type, i ) );
775  save_geomodel_mesh_entity< ENTITY< DIMENSION > >( entity, filenames );
776  } );
777  logger->set_quiet( logger_status );
778  }
779 
780  template< index_t DIMENSION >
781  void save_all_geomodel_mesh_entities_base(
782  const GeoModel< DIMENSION >& geomodel,
783  std::vector< std::string >& filenames )
784  {
785  save_geomodel_mesh_entities< Corner, DIMENSION >( geomodel, filenames );
786  save_geomodel_mesh_entities< Line, DIMENSION >( geomodel, filenames );
787  save_geomodel_mesh_entities< Surface, DIMENSION >( geomodel, filenames );
788  }
789 
790  template< index_t DIMENSION >
791  void save_all_geomodel_mesh_entities(
792  const GeoModel< DIMENSION >& geomodel,
793  std::vector< std::string >& filenames );
794 
795  template< >
796  void save_all_geomodel_mesh_entities(
797  const GeoModel2D& geomodel,
798  std::vector< std::string >& filenames )
799  {
800  save_all_geomodel_mesh_entities_base( geomodel, filenames );
801  }
802  template< >
803  void save_all_geomodel_mesh_entities(
804  const GeoModel3D& geomodel,
805  std::vector< std::string >& filenames )
806  {
807  save_all_geomodel_mesh_entities_base( geomodel, filenames );
808  save_geomodel_mesh_entities< Region, 3 >( geomodel, filenames );
809  }
810 
811  template< index_t DIMENSION >
812  index_t nb_mesh_entities( const GeoModel< DIMENSION >& geomodel );
813 
814  template< >
815  index_t nb_mesh_entities( const GeoModel2D& geomodel )
816  {
817  return geomodel.nb_corners() + geomodel.nb_lines() + geomodel.nb_surfaces();
818  }
819 
820  template< >
821  index_t nb_mesh_entities( const GeoModel3D& geomodel )
822  {
823  return geomodel.nb_corners() + geomodel.nb_lines() + geomodel.nb_surfaces()
824  + geomodel.nb_regions();
825  }
826 
827  index_t find_dimension( const std::string& mesh_entities_filename )
828  {
829  GEO::LineInput file_line { mesh_entities_filename };
830  while( !file_line.eof() && file_line.get_line() ) {
831  file_line.get_fields();
832  if( file_line.nb_fields() == 2 ) {
833  if( file_line.field_matches( 0, "Dimension" ) ) {
834  return file_line.field_as_uint( 1 );
835  }
836  }
837  }
838  return 3;
839  }
840 
841  template< index_t DIMENSION >
842  class GeoModelHandlerGM final : public GeoModelIOHandler< DIMENSION > {
843  public:
844  void load( const std::string& filename, GeoModel< DIMENSION >& geomodel ) final
845  {
846  auto pwd = GEO::FileSystem::get_current_working_directory();
847  GEO::FileSystem::set_current_working_directory(
848  GEO::FileSystem::dir_name( filename ) );
849  GeoModelBuilderGM< DIMENSION > builder { geomodel,
850  GEO::FileSystem::base_name(
851  filename, false ) };
852  builder.build_geomodel();
853  GEO::FileSystem::set_current_working_directory( pwd );
854  }
855 
856  void save(
857  const GeoModel< DIMENSION >& geomodel,
858  const std::string& filename ) final
859  {
860  ZipFile zf { filename };
861 
862  const std::string mesh_entity_file { "mesh_entities.txt" };
863  save_mesh_entities( geomodel, mesh_entity_file );
864  zf.add_file( mesh_entity_file );
865  GEO::FileSystem::delete_file( mesh_entity_file );
866 
867  const std::string geological_entity_file { "geological_entities.txt" };
868  save_geological_entities( geomodel, geological_entity_file );
869  zf.add_file( geological_entity_file );
870  GEO::FileSystem::delete_file( geological_entity_file );
871 
872  auto nb_mesh_entites = nb_mesh_entities( geomodel );
873  std::vector< std::string > filenames;
874  filenames.reserve( nb_mesh_entites );
875  Logger::instance()->set_quiet( true );
876  save_all_geomodel_mesh_entities( geomodel, filenames );
877  Logger::instance()->set_quiet( false );
878  std::sort( filenames.begin(), filenames.end() );
879  zip_files( filenames, zf );
880  }
881 
882  index_t dimension( const std::string& filename ) const final
883  {
884  UnZipFile uz { filename };
885  const std::string mesh_entity_file( "mesh_entities.txt" );
886  uz.get_file( mesh_entity_file );
887  auto dimension = find_dimension( mesh_entity_file );
888  auto ok = GEO::FileSystem::delete_file( mesh_entity_file );
889  ringmesh_unused( ok );
890  return dimension;
891  }
892 
893  virtual ~GeoModelHandlerGM() = default;
894  private:
895  void save_geomodel_regions(
896  const GeoModel< DIMENSION >& geomodel,
897  std::vector< std::string >& filenames );
898  };
899 
900  ALIAS_2D_AND_3D (GeoModelHandlerGM);
901 }
Abstract base class for GeoModelMeshEntity.
void get_file(const std::string &filename)
Definition: zip_file.cpp:213
static std::string geol_name(GEOL_FEATURE feature)
The GeologicalEntityType described the type of the Geological entities User can defined there own Geo...
Definition: entity_type.h:137
virtual const GeoModelMeshEntity< DIMENSION > & mesh_entity(const gmme_id &id) const
Generic access to a meshed entity.
Definition: geomodel.cpp:131
void ringmesh_unused(const T &)
Definition: common.h:105
void add_file(const std::string &filename)
Definition: zip_file.cpp:101
ALIAS_2D_AND_3D(Box)
static MeshEntityType type_name_static()
Abstract interface class to load and build GeoModels from files.
Entity_type_template type() const
Definition: entity_type.h:202
index_t nb_geological_entity_types() const
Returns the index of the geological entity type storage.
Definition: geomodel.h:146
std::string get_current_filename()
Definition: zip_file.cpp:228
const std::string & name() const
Gets the name of the GeoModel.
Definition: geomodel.h:111
static MeshEntityType type_name_static()
const std::string & name() const
static GEO::Logger * instance()
Definition: logger.h:81
static MeshEntityType type_name_static()
const gmme_id & child_gmme(index_t x) const
const GeologicalEntityType & geological_entity_type(index_t index) const
Definition: geomodel.h:152
index_t nb_corners() const
Definition: geomodel.h:201
index_t nb_lines() const
Definition: geomodel.h:205
#define ringmesh_assert(x)
index_t nb_surfaces() const
Definition: geomodel.h:209
A GeoModelEntity of type REGION.
The MeshEntityType described the type of the meshed entities There are 4 MeshEntityTypes correspondin...
Definition: entity_type.h:117
This template is a specialization of a gme_id to the GeoModelGeologicalEntity.
Definition: entity_type.h:262
Classes to build GeoModel from various inputs.
Definition: algorithm.h:48
const GeoModelGeologicalEntity< DIMENSION > & geological_entity(gmge_id id) const
Returns a const reference the identified GeoModelGeologicalEntity.
Definition: geomodel.h:165
virtual index_t nb_mesh_entities(const MeshEntityType &type) const
Returns the number of mesh entities of the given type.
Definition: geomodel.cpp:108
index_t index() const
Definition: entity_type.h:197
This template is a specialization of a gme_id to the GeoModelMeshEntity.
Definition: entity_type.h:285
index_t nb_geological_entities(const GeologicalEntityType &type) const
Returns the number of geological entities of the given type.
Definition: geomodel.h:136
void parallel_for(index_t size, const ACTION &action)
Definition: common.h:244
const char EOL
Definition: io.h:45