Line data Source code
1 : /*
2 : * Copyright (c) 2009-2015: G-CSC, Goethe University Frankfurt
3 : * Author: Sebastian Reiter
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 : #include <string>
34 : #include "file_io.h"
35 : #include "lib_grid/algorithms/attachment_util.h"
36 : #include "common/util/path_provider.h"
37 : #include "common/util/file_util.h"
38 : #include "common/util/string_util.h"
39 : #include "lib_grid/parallelization/distributed_grid.h"
40 : #include "lib_grid/algorithms/subset_util.h"
41 : #include "lib_grid/tools/surface_view.h"
42 :
43 : #include "file_io_2df.h"
44 : #include "file_io_art.h"
45 : #include "file_io_asc.h"
46 : #include "file_io_txt.h"
47 : #include "file_io_tetgen.h"
48 : #include "file_io_obj.h"
49 : #include "file_io_lgm.h"
50 : #include "file_io_lgb.h"
51 : #include "file_io_ng.h"
52 : #include "file_io_ug.h"
53 : #include "file_io_dump.h"
54 : #include "file_io_ncdf.h"
55 : #include "file_io_ugx.h"
56 : #include "file_io_msh.h"
57 : #include "file_io_stl.h"
58 : #include "file_io_tikz.h"
59 : #include "file_io_vtu.h"
60 : #include "file_io_swc.h"
61 : #include "file_io_grdecl.h"
62 :
63 : #ifdef UG_PARALLEL
64 : #include "pcl/pcl_process_communicator.h"
65 : #include "pcl/pcl_util.h"
66 : #endif
67 :
68 : using namespace std;
69 :
70 : namespace ug
71 : {
72 :
73 : ////////////////////////////////////////////////////////////////////////////////
74 : // this method performs the actual loading.
75 0 : static bool LoadGrid3d_IMPL(Grid& grid, ISubsetHandler* pSH,
76 : const char* filename, AVector3& aPos)
77 : {
78 0 : string strExt = GetFilenameExtension(string(filename));
79 0 : strExt = ToLower(strExt);
80 :
81 : bool bAutoassignFaces = false;
82 : bool bSuccess = false;
83 0 : if(strExt.compare("txt") == 0)
84 : {
85 : bAutoassignFaces = true;
86 0 : bSuccess = LoadGridFromTXT(grid, filename, aPos);
87 : }
88 0 : else if(strExt.compare("grdecl") == 0)
89 : {
90 : bAutoassignFaces = true;
91 0 : bSuccess = LoadGridFromGRDECL(grid, filename, aPos);
92 : }
93 0 : else if(strExt.compare("obj") == 0)
94 0 : bSuccess = LoadGridFromOBJ(grid, filename, aPos, NULL, pSH);
95 0 : else if(strExt.compare("lgb") == 0)
96 : {
97 : int numSHs = 0;
98 0 : if(pSH)
99 : numSHs = 1;
100 :
101 0 : bSuccess = LoadGridFromLGB(grid, filename, &pSH, numSHs, NULL, aPos);
102 : }
103 0 : else if(strExt.compare("2df") == 0)
104 0 : bSuccess = LoadGridFrom2DF(grid, filename, pSH, aPos);
105 0 : else if(strExt.compare("stl") == 0)
106 0 : bSuccess = LoadGridFromSTL(grid, filename, pSH, aPos);
107 0 : else if(strExt.compare("net") == 0)
108 0 : bSuccess = LoadGridFromART(grid, filename, pSH, aPos);
109 0 : else if(strExt.compare("art") == 0)
110 0 : bSuccess = LoadGridFromART(grid, filename, pSH, aPos);
111 0 : else if(strExt.compare("dat") == 0)
112 0 : bSuccess = LoadGridFromART(grid, filename, pSH, aPos);
113 0 : else if(strExt.compare("lgm") == 0)
114 0 : bSuccess = ImportGridFromLGM(grid, filename, aPos, pSH);
115 0 : else if(strExt.compare("ng") == 0)
116 0 : bSuccess = ImportGridFromNG(grid, filename, aPos, pSH);
117 0 : else if(strExt.compare("dump") == 0)
118 : {
119 0 : bSuccess = LoadGridFromDUMP(grid, filename, pSH, aPos);
120 : }
121 0 : else if(strExt.compare("ele") == 0)
122 0 : return LoadGridFromELE(grid, filename, pSH, aPos);
123 0 : else if(strExt.compare("msh") == 0)
124 0 : bSuccess = LoadGridFromMSH(grid, filename, pSH, aPos);
125 0 : else if(strExt.compare("smesh") == 0)
126 0 : bSuccess = LoadGridFromSMESH(grid, filename, aPos, pSH);
127 0 : else if(strExt.compare("asc") == 0){
128 0 : bSuccess = LoadGridFromASC(grid, filename, aPos);
129 : bAutoassignFaces = true;
130 : }
131 0 : else if(strExt.compare("swc") == 0){
132 0 : bSuccess = LoadGridFromSWC(grid, pSH, filename, aPos);
133 : }
134 :
135 0 : if(bAutoassignFaces && pSH)
136 : pSH->assign_subset(grid.faces_begin(), grid.faces_end(), 0);
137 :
138 : return bSuccess;
139 : }
140 :
141 :
142 0 : static bool LoadGrid3d(Grid& grid, ISubsetHandler* psh,
143 : const char* filename, APosition1& aPos)
144 : {
145 : APosition aPosTMP;
146 : grid.attach_to_vertices(aPosTMP);
147 0 : if(LoadGrid3d_IMPL(grid, psh, filename, aPosTMP)){
148 : // convert the position data from 3d to the required dimension.
149 0 : ConvertMathVectorAttachmentValues<Vertex>(grid, aPosTMP, aPos);
150 : grid.detach_from_vertices(aPosTMP);
151 0 : return true;
152 : }
153 : grid.detach_from_vertices(aPosTMP);
154 : return false;
155 : }
156 :
157 0 : static bool LoadGrid3d(Grid& grid, ISubsetHandler* psh,
158 : const char* filename, APosition2& aPos)
159 : {
160 : APosition aPosTMP;
161 : grid.attach_to_vertices(aPosTMP);
162 0 : if(LoadGrid3d_IMPL(grid, psh, filename, aPosTMP)){
163 : // convert the position data from 3d to the required dimension.
164 0 : ConvertMathVectorAttachmentValues<Vertex>(grid, aPosTMP, aPos);
165 : grid.detach_from_vertices(aPosTMP);
166 0 : return true;
167 : }
168 : grid.detach_from_vertices(aPosTMP);
169 : return false;
170 : }
171 :
172 : static bool LoadGrid3d(Grid& grid, ISubsetHandler* psh,
173 : const char* filename, APosition3& aPos)
174 : {
175 0 : return LoadGrid3d_IMPL(grid, psh, filename, aPos);
176 : }
177 :
178 : ////////////////////////////////////////////////////////////////////////////////
179 : /// This method calls specific load routines or delegates loading to LoadGrid3d
180 : template <class TAPos>
181 0 : static bool LoadGrid(Grid& grid, ISubsetHandler* psh,
182 : const char* filename, TAPos& aPos,
183 : int procId)
184 : {
185 : // For convenience, we support multiple different standard paths, from which
186 : // grids may be loaded. We thus first check, where the specified file is
187 : // located and load it from that location afterwards.
188 : bool loadingGrid = true;
189 : #ifdef UG_PARALLEL
190 : if((procId != -1) && (pcl::ProcRank() != procId))
191 : loadingGrid = false;
192 : #endif
193 :
194 0 : grid.message_hub()->post_message(GridMessage_Creation(GMCT_CREATION_STARTS, procId));
195 : bool retVal = false;
196 : if(loadingGrid){
197 : // Now perform the actual loading.
198 : // first all load methods, which do accept template position types are
199 : // handled. Then all those which only work with 3d position types are processed.
200 0 : string tfile = FindFileInStandardPaths(filename);
201 0 : if(!tfile.empty()){
202 0 : if(tfile.find(".ugx") != string::npos){
203 0 : if(psh)
204 0 : retVal = LoadGridFromUGX(grid, *psh, tfile.c_str(), aPos);
205 : else{
206 : // we have to create a temporary subset handler
207 0 : SubsetHandler shTmp(grid);
208 0 : retVal = LoadGridFromUGX(grid, shTmp, tfile.c_str(), aPos);
209 0 : }
210 : }
211 0 : else if(tfile.find(".vtu") != string::npos){
212 0 : if(psh)
213 0 : retVal = LoadGridFromVTU(grid, *psh, tfile.c_str(), aPos);
214 : else{
215 : // we have to create a temporary subset handler
216 0 : SubsetHandler shTmp(grid);
217 0 : retVal = LoadGridFromVTU(grid, shTmp, tfile.c_str(), aPos);
218 0 : }
219 : }
220 : else{
221 : // now we'll handle those methods, which only support 3d position types.
222 0 : retVal = LoadGrid3d(grid, psh, tfile.c_str(), aPos);
223 : }
224 : }
225 : }
226 :
227 : // declare global attachments on all processors
228 : #ifdef UG_PARALLEL
229 : GlobalAttachments::SynchronizeDeclaredGlobalAttachments(grid, procId);
230 : #endif
231 :
232 0 : grid.message_hub()->post_message(GridMessage_Creation(GMCT_CREATION_STOPS, procId));
233 :
234 :
235 : #ifdef UG_PARALLEL
236 : pcl::ProcessCommunicator procCom;
237 : if(procId == -1)
238 : retVal = pcl::AllProcsTrue(retVal, procCom);
239 : else
240 : retVal = pcl::OneProcTrue(retVal, procCom);
241 : #endif
242 :
243 0 : return retVal;
244 : }
245 :
246 : template <class TAPos>
247 0 : static bool LoadGrid(Grid& grid, SPProjectionHandler* ph, size_t& num_ph, ISubsetHandler* psh, std::vector<std::string> additionalSHNames,
248 : std::vector<SmartPtr<ISubsetHandler>> ash, const char* filename, TAPos& aPos, int procId)
249 : {
250 : // For convenience, we support multiple different standard paths, from which
251 : // grids may be loaded. We thus first check, where the specified file is
252 : // located and load it from that location afterwards.
253 : bool loadingGrid = true;
254 : #ifdef UG_PARALLEL
255 : if((procId != -1) && (pcl::ProcRank() != procId))
256 : loadingGrid = false;
257 : #endif
258 :
259 0 : grid.message_hub()->post_message(GridMessage_Creation(GMCT_CREATION_STARTS, procId));
260 :
261 : bool retVal = false;
262 : if(loadingGrid){
263 : // Now perform the actual loading.
264 : // first all load methods, which do accept template position types are
265 : // handled. Then all those which only work with 3d position types are processed.
266 0 : string tfile = FindFileInStandardPaths(filename);
267 0 : if(!tfile.empty()){
268 0 : if(tfile.find(".ugx") != string::npos){
269 0 : if(psh)
270 0 : retVal = LoadGridFromUGX(grid, *ph, num_ph, *psh, additionalSHNames, ash, tfile.c_str(), aPos);
271 : else{
272 : // we have to create a temporary subset handler
273 0 : SubsetHandler shTmp(grid);
274 0 : retVal = LoadGridFromUGX(grid, *ph, num_ph, shTmp, additionalSHNames, ash, tfile.c_str(), aPos);
275 0 : }
276 : }
277 :
278 0 : else if(tfile.find(".vtu") != string::npos){
279 0 : if(psh)
280 0 : retVal = LoadGridFromVTU(grid, *psh, tfile.c_str(), aPos);
281 : else{
282 : // we have to create a temporary subset handler
283 0 : SubsetHandler shTmp(grid);
284 0 : retVal = LoadGridFromVTU(grid, shTmp, tfile.c_str(), aPos);
285 0 : }
286 : }
287 : else{
288 : // now we'll handle those methods, which only support 3d position types.
289 0 : retVal = LoadGrid3d(grid, psh, tfile.c_str(), aPos);
290 : }
291 :
292 : }
293 : }
294 :
295 : // declare global attachments on all processors
296 : #ifdef UG_PARALLEL
297 : GlobalAttachments::SynchronizeDeclaredGlobalAttachments(grid, procId);
298 : #endif
299 :
300 0 : grid.message_hub()->post_message(GridMessage_Creation(GMCT_CREATION_STOPS, procId));
301 :
302 : #ifdef UG_PARALLEL
303 : pcl::ProcessCommunicator procCom;
304 : if(procId == -1)
305 : retVal = pcl::AllProcsTrue(retVal, procCom);
306 : else
307 : {
308 : procCom.broadcast(num_ph, procId);
309 : retVal = pcl::OneProcTrue(retVal, procCom);
310 : }
311 : #endif
312 :
313 0 : return retVal;
314 : }
315 :
316 : ////////////////////////////////////////////////////////////////////////////////
317 : template <class TAPos>
318 0 : bool LoadGridFromFile(Grid& grid, SPProjectionHandler& ph, size_t& num_ph, ISubsetHandler& sh, vector<string> additionalSHNames,
319 : vector<SmartPtr<ISubsetHandler>> ash, const char* filename, TAPos& aPos, int procId)
320 : {
321 0 : return LoadGrid(grid, &ph, num_ph, &sh, additionalSHNames, ash, filename, aPos, procId);
322 : }
323 :
324 : template <class TAPos>
325 0 : bool LoadGridFromFile(Grid& grid, ISubsetHandler& sh,
326 : const char* filename, TAPos& aPos, int procId)
327 : {
328 0 : return LoadGrid(grid, &sh, filename, aPos, procId);
329 : }
330 :
331 : template <class TAPos>
332 0 : bool LoadGridFromFile(Grid& grid, const char* filename, TAPos& aPos, int procId)
333 : {
334 0 : return LoadGrid(grid, NULL, filename, aPos, procId);
335 : }
336 :
337 0 : bool LoadGridFromFile(Grid& grid, ISubsetHandler& sh, const char* filename, int procId)
338 : {
339 0 : return LoadGrid(grid, &sh, filename, aPosition, procId);
340 : }
341 :
342 0 : bool LoadGridFromFile(Grid& grid, const char* filename, int procId)
343 : {
344 0 : return LoadGrid(grid, NULL, filename, aPosition, procId);
345 : }
346 :
347 :
348 : ////////////////////////////////////////////////////////////////////////////////
349 : ////////////////////////////////////////////////////////////////////////////////
350 : // this method performs the actual save.
351 0 : static bool SaveGrid3d_IMPL(Grid& grid, ISubsetHandler* pSH,
352 : const char* filename, AVector3& aPos)
353 : {
354 0 : string strName = filename;
355 0 : if(strName.find(".txt") != string::npos)
356 0 : return SaveGridToTXT(grid, filename, aPos);
357 0 : if(strName.find(".2df") != string::npos)
358 0 : return SaveGridTo2DF(grid, filename, pSH, aPos);
359 0 : else if(strName.find(".obj") != string::npos)
360 0 : return SaveGridToOBJ(grid, filename, aPos, NULL, pSH);
361 0 : else if(strName.find(".lgb") != string::npos)
362 : {
363 : int numSHs = 0;
364 0 : if(pSH)
365 : numSHs = 1;
366 :
367 0 : return SaveGridToLGB(grid, filename, &pSH, numSHs, NULL, aPos);
368 : }
369 0 : else if(strName.find(".ele") != string::npos)
370 0 : return SaveGridToELE(grid, filename, pSH, aPos);
371 0 : else if(strName.find(".net") != string::npos)
372 0 : return SaveGridToART(grid, filename, pSH, aPos);
373 0 : else if(strName.find(".art") != string::npos)
374 0 : return SaveGridToART(grid, filename, pSH, aPos);
375 0 : else if(strName.find(".ncdf") != string::npos)
376 0 : return SaveGridToNCDF(grid, filename, pSH, aPos);
377 0 : else if(strName.find(".stl") != string::npos)
378 0 : return SaveGridToSTL(grid, filename, pSH, aPos);
379 0 : else if(strName.find(".smesh") != string::npos)
380 0 : return ExportGridToSMESH(grid, filename, aPos, pSH);
381 : else if((strName.find(".tikz") != string::npos)
382 0 : || (strName.find(".tex") != string::npos))
383 : {
384 0 : return ExportGridToTIKZ(grid, filename, pSH, aPos);
385 : }
386 0 : else if (strName.find(".swc") != string::npos)
387 0 : return ExportGridToSWC(grid, pSH, filename, aPos);
388 :
389 : return false;
390 : }
391 :
392 : ////////////////////////////////////////////////////////////////////////////////
393 0 : static bool SaveGrid3d(Grid& grid, ISubsetHandler* psh,
394 : const char* filename, APosition1& aPos)
395 : {
396 : APosition aPosTMP;
397 : grid.attach_to_vertices(aPosTMP);
398 : // convert the position data from the given dimension to 3d
399 0 : ConvertMathVectorAttachmentValues<Vertex>(grid, aPos, aPosTMP);
400 0 : if(SaveGrid3d_IMPL(grid, psh, filename, aPosTMP)){
401 : grid.detach_from_vertices(aPosTMP);
402 0 : return true;
403 : }
404 : grid.detach_from_vertices(aPosTMP);
405 : return false;
406 : }
407 :
408 : ////////////////////////////////////////////////////////////////////////////////
409 0 : static bool SaveGrid3d(Grid& grid, ISubsetHandler* psh,
410 : const char* filename, APosition2& aPos)
411 : {
412 : APosition aPosTMP;
413 : grid.attach_to_vertices(aPosTMP);
414 : // convert the position data from the given dimension to 3d
415 0 : ConvertMathVectorAttachmentValues<Vertex>(grid, aPos, aPosTMP);
416 0 : if(SaveGrid3d_IMPL(grid, psh, filename, aPosTMP)){
417 : grid.detach_from_vertices(aPosTMP);
418 0 : return true;
419 : }
420 : grid.detach_from_vertices(aPosTMP);
421 : return false;
422 : }
423 :
424 : ////////////////////////////////////////////////////////////////////////////////
425 : static bool SaveGrid3d(Grid& grid, ISubsetHandler* psh,
426 : const char* filename, APosition3& aPos)
427 : {
428 0 : return SaveGrid3d_IMPL(grid, psh, filename, aPos);
429 : }
430 :
431 : ////////////////////////////////////////////////////////////////////////////////
432 : template <class TAPos>
433 0 : static bool SaveGrid(Grid& grid, ISubsetHandler* psh,
434 : const char* filename, TAPos& aPos)
435 : {
436 0 : string strName = filename;
437 0 : if(strName.find(".ugx") != string::npos){
438 : #if (defined UG_PARALLEL && defined UG_DEBUG)
439 : std::size_t found=strName.find(".ugx");
440 : strName=strName.replace(found, 4, "");
441 : int procRank=pcl::ProcRank();
442 : strName=strName.append("_p");
443 : strName=strName.append(std::to_string(procRank));
444 : strName.append(".ugx");
445 : #endif
446 :
447 0 : if(psh)
448 0 : return SaveGridToUGX(grid, *psh, strName.c_str(), aPos);
449 : else {
450 0 : SubsetHandler shTmp(grid);
451 0 : return SaveGridToUGX(grid, shTmp, strName.c_str(), aPos);
452 0 : }
453 : }
454 0 : else if(strName.find(".vtu") != string::npos){
455 : #if (defined UG_PARALLEL && defined UG_DEBUG)
456 : std::size_t found=strName.find(".vtu");
457 : strName=strName.replace(found, 4, "");
458 : strName=strName.append("_p");
459 : strName=strName.append(std::to_string(pcl::ProcRank()));
460 : strName.append(".vtu");
461 : #endif
462 0 : return SaveGridToVTU(grid, psh, strName.c_str(), aPos);
463 : }
464 : else
465 0 : return SaveGrid3d(grid, psh, filename, aPos);
466 : }
467 :
468 :
469 : ////////////////////////////////////////////////////////////////////////////////
470 : template <class TAPos>
471 0 : bool SaveGridToFile(Grid& grid, ISubsetHandler& sh,
472 : const char* filename, TAPos& aPos)
473 : {
474 0 : return SaveGrid(grid, &sh, filename, aPos);
475 : }
476 :
477 : template <class TAPos>
478 0 : bool SaveGridToFile(Grid& grid, const char* filename, TAPos& aPos)
479 : {
480 0 : return SaveGrid(grid, NULL, filename, aPos);
481 : }
482 :
483 0 : bool SaveGridToFile(Grid& grid, ISubsetHandler& sh, const char* filename)
484 : {
485 : // check whether one of the standard attachments is attached and call
486 : // SaveGrid with that attachment
487 0 : if(grid.has_vertex_attachment(aPosition))
488 0 : return SaveGrid(grid, &sh, filename, aPosition);
489 0 : if(grid.has_vertex_attachment(aPosition2))
490 0 : return SaveGrid(grid, &sh, filename, aPosition2);
491 0 : if(grid.has_vertex_attachment(aPosition1))
492 0 : return SaveGrid(grid, &sh, filename, aPosition1);
493 :
494 : return false;
495 : }
496 :
497 0 : bool SaveGridToFile(Grid& grid, const char* filename)
498 : {
499 : // check whether one of the standard attachments is attached and call
500 : // SaveGrid with that attachment
501 0 : if(grid.has_vertex_attachment(aPosition))
502 0 : return SaveGrid(grid, NULL, filename, aPosition);
503 0 : if(grid.has_vertex_attachment(aPosition2))
504 0 : return SaveGrid(grid, NULL, filename, aPosition2);
505 0 : if(grid.has_vertex_attachment(aPosition1))
506 0 : return SaveGrid(grid, NULL, filename, aPosition1);
507 : return false;
508 : }
509 :
510 0 : bool SaveGridHierarchyTransformed(MultiGrid& mg, ISubsetHandler& sh,
511 : const char* filename, number offset)
512 : {
513 : PROFILE_FUNC_GROUP("grid");
514 : APosition aPos;
515 : // uses auto-attach
516 0 : Grid::AttachmentAccessor<Vertex, APosition> aaPos(mg, aPos, true);
517 :
518 : // copy the existing position to aPos. We take care of dimension differences.
519 : // Note: if the method was implemented for domains, this could be implemented
520 : // in a nicer way.
521 0 : if(mg.has_vertex_attachment(aPosition))
522 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition, aPos);
523 0 : else if(mg.has_vertex_attachment(aPosition2))
524 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition2, aPos);
525 0 : else if(mg.has_vertex_attachment(aPosition1))
526 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition1, aPos);
527 :
528 : // iterate through all vertices and apply an offset depending on their level.
529 0 : for(size_t lvl = 0; lvl < mg.num_levels(); ++lvl){
530 0 : for(VertexIterator iter = mg.begin<Vertex>(lvl);
531 0 : iter != mg.end<Vertex>(lvl); ++iter)
532 : {
533 0 : aaPos[*iter].z() += (number)lvl * offset;
534 : }
535 : }
536 :
537 : // finally save the grid
538 : bool writeSuccess = SaveGridToFile(mg, sh, filename, aPos);
539 :
540 : // clean up
541 : mg.detach_from_vertices(aPos);
542 :
543 0 : return writeSuccess;
544 : }
545 :
546 0 : bool SaveGridHierarchyTransformed(MultiGrid& mg, const char* filename,
547 : number offset)
548 : {
549 : PROFILE_FUNC_GROUP("grid");
550 : // cast away constness
551 : SubsetHandler& sh = mg.get_hierarchy_handler();
552 :
553 : APosition aPos;
554 : // uses auto-attach
555 0 : Grid::AttachmentAccessor<Vertex, APosition> aaPos(mg, aPos, true);
556 :
557 : // copy the existing position to aPos. We take care of dimension differences.
558 : // Note: if the method was implemented for domains, this could be implemented
559 : // in a nicer way.
560 0 : if(mg.has_vertex_attachment(aPosition))
561 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition, aPos);
562 0 : else if(mg.has_vertex_attachment(aPosition2))
563 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition2, aPos);
564 0 : else if(mg.has_vertex_attachment(aPosition1))
565 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition1, aPos);
566 :
567 : // iterate through all vertices and apply an offset depending on their level.
568 0 : for(size_t lvl = 0; lvl < mg.num_levels(); ++lvl){
569 0 : for(VertexIterator iter = mg.begin<Vertex>(lvl);
570 0 : iter != mg.end<Vertex>(lvl); ++iter)
571 : {
572 0 : aaPos[*iter].z() += (number)lvl * offset;
573 : }
574 : }
575 :
576 : // finally save the grid
577 0 : bool writeSuccess = SaveGridToFile(mg, sh, filename, aPos);
578 :
579 : // clean up
580 : mg.detach_from_vertices(aPos);
581 :
582 0 : return writeSuccess;
583 : }
584 :
585 : template <class TElem>
586 0 : static void AssignSubsetsByInterfaceType(SubsetHandler& sh, MultiGrid& mg)
587 : {
588 : const int siNormal = 0;
589 : const int siHMaster = 1;
590 : const int siHSlave = 1 << 1;
591 : const int siVMaster = 1 << 2;
592 : const int siVSlave = 1 << 3;
593 :
594 0 : const char* subsetNames[] = {"normal", "hmaster", "hslave", "hslave+hmaster",
595 : "vmaster", "vmaster+hmaster", "vmaster+hslave",
596 : "vmaster+hslave+hmaster", "vslave", "vslave+hmaster",
597 : "vslave+hslave", "vslave+hslave+hmaster",
598 : "vslave+vmaster", "vslave+vmaster+hmaster",
599 : "vslave+vmaster+hslave", "vslave+vmaster+hmaster+hslave"};
600 :
601 0 : for(int i = 0; i < 16; ++i)
602 0 : sh.subset_info(i).name = subsetNames[i];
603 :
604 : typedef typename Grid::traits<TElem>::iterator TIter;
605 0 : for(TIter iter = mg.begin<TElem>(); iter != mg.end<TElem>(); ++iter){
606 : int status = ES_NONE;
607 :
608 : #ifdef UG_PARALLEL
609 : DistributedGridManager* distGridMgr = mg.distributed_grid_manager();
610 : if(distGridMgr)
611 : status = distGridMgr->get_status(*iter);
612 : #endif
613 :
614 : int index = siNormal;
615 : if(status & ES_H_MASTER)
616 : index |= siHMaster;
617 : if(status & ES_H_SLAVE)
618 : index |= siHSlave;
619 : if(status & ES_V_MASTER)
620 : index |= siVMaster;
621 : if(status & ES_V_SLAVE)
622 : index |= siVSlave;
623 :
624 0 : sh.assign_subset(*iter, index);
625 : }
626 0 : }
627 :
628 0 : bool SaveParallelGridLayout(MultiGrid& mg, const char* filename, number offset)
629 : {
630 : PROFILE_FUNC_GROUP("grid");
631 :
632 : APosition aPos;
633 : // uses auto-attach
634 0 : Grid::AttachmentAccessor<Vertex, APosition> aaPos(mg, aPos, true);
635 :
636 : // copy the existing position to aPos. We take care of dimension differences.
637 : // Note: if the method was implemented for domains, this could be implemented
638 : // in a nicer way.
639 0 : if(mg.has_vertex_attachment(aPosition))
640 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition, aPos);
641 0 : else if(mg.has_vertex_attachment(aPosition2))
642 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition2, aPos);
643 0 : else if(mg.has_vertex_attachment(aPosition1))
644 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition1, aPos);
645 :
646 : // iterate through all vertices and apply an offset depending on their level.
647 0 : for(size_t lvl = 0; lvl < mg.num_levels(); ++lvl){
648 0 : for(VertexIterator iter = mg.begin<Vertex>(lvl);
649 0 : iter != mg.end<Vertex>(lvl); ++iter)
650 : {
651 0 : aaPos[*iter].z() += (number)lvl * offset;
652 : }
653 : }
654 :
655 : // create a subset handler which holds different subsets for the different interface types
656 0 : SubsetHandler sh(mg);
657 :
658 0 : AssignSubsetsByInterfaceType<Vertex>(sh, mg);
659 0 : AssignSubsetsByInterfaceType<Edge>(sh, mg);
660 0 : AssignSubsetsByInterfaceType<Face>(sh, mg);
661 0 : AssignSubsetsByInterfaceType<Volume>(sh, mg);
662 :
663 0 : AssignSubsetColors(sh);
664 0 : EraseEmptySubsets(sh);
665 :
666 : // finally save the grid
667 : bool writeSuccess = SaveGridToFile(mg, sh, filename, aPos);
668 :
669 : // clean up
670 : mg.detach_from_vertices(aPos);
671 :
672 0 : return writeSuccess;
673 0 : }
674 :
675 : template <class TElem>
676 0 : static void AssignSubsetsBySurfaceViewState(SubsetHandler& sh, const SurfaceView& sv,
677 : MultiGrid& mg)
678 : {
679 : typedef typename Grid::traits<TElem>::iterator TIter;
680 0 : for(TIter iter = mg.begin<TElem>(); iter != mg.end<TElem>(); ++iter){
681 : TElem* e = *iter;
682 :
683 0 : sh.assign_subset(e, sv.surface_state(e).get());
684 : }
685 0 : for(int i = 0; i < sh.num_subsets(); ++i)
686 0 : sh.subset_info(i).name = "unknown";
687 0 : sh.subset_info(SurfaceView::MG_SHADOW_PURE).name = "shadow-pure";
688 0 : sh.subset_info(SurfaceView::MG_SURFACE_PURE).name = "surface-pure";
689 0 : sh.subset_info(SurfaceView::MG_SURFACE_RIM).name = "surface-rim";
690 0 : sh.subset_info(SurfaceView::MG_SHADOW_RIM_COPY).name = "shadow-rim-copy";
691 0 : sh.subset_info(SurfaceView::MG_SHADOW_RIM_NONCOPY).name = "shadow-rim-noncopy";
692 : //EraseEmptySubsets(sh);
693 0 : }
694 :
695 0 : bool SaveSurfaceViewTransformed(MultiGrid& mg, const SurfaceView& sv,
696 : const char* filename, number offset)
697 : {
698 : PROFILE_FUNC_GROUP("grid");
699 :
700 : APosition aPos;
701 : // uses auto-attach
702 0 : Grid::AttachmentAccessor<Vertex, APosition> aaPos(mg, aPos, true);
703 :
704 : // copy the existing position to aPos. We take care of dimension differences.
705 : // Note: if the method was implemented for domains, this could be implemented
706 : // in a nicer way.
707 0 : if(mg.has_vertex_attachment(aPosition))
708 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition, aPos);
709 0 : else if(mg.has_vertex_attachment(aPosition2))
710 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition2, aPos);
711 0 : else if(mg.has_vertex_attachment(aPosition1))
712 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition1, aPos);
713 :
714 : // iterate through all vertices and apply an offset depending on their level.
715 0 : for(size_t lvl = 0; lvl < mg.num_levels(); ++lvl){
716 0 : for(VertexIterator iter = mg.begin<Vertex>(lvl);
717 0 : iter != mg.end<Vertex>(lvl); ++iter)
718 : {
719 0 : aaPos[*iter].z() += (number)lvl * offset;
720 : }
721 : }
722 :
723 : // create a subset handler which holds different subsets for the different interface types
724 0 : SubsetHandler sh(mg);
725 :
726 0 : AssignSubsetsBySurfaceViewState<Vertex>(sh, sv, mg);
727 0 : AssignSubsetsBySurfaceViewState<Edge>(sh, sv, mg);
728 0 : AssignSubsetsBySurfaceViewState<Face>(sh, sv, mg);
729 0 : AssignSubsetsBySurfaceViewState<Volume>(sh, sv, mg);
730 :
731 0 : AssignSubsetColors(sh);
732 0 : EraseEmptySubsets(sh);
733 :
734 : // finally save the grid
735 : bool writeSuccess = SaveGridToFile(mg, sh, filename, aPos);
736 :
737 : // clean up
738 : mg.detach_from_vertices(aPos);
739 :
740 0 : return writeSuccess;
741 0 : }
742 :
743 : template<class TElem>
744 0 : void CopyGridLevelElements(MultiGrid& srcMG, Grid& destGrid,
745 : ISubsetHandler& srcSH, ISubsetHandler& destSH,
746 : int lvl, AVertex& aNewVrt)
747 : {
748 : Grid::VertexAttachmentAccessor<AVertex> aaNewVrt(srcMG, aNewVrt);
749 0 : GridObjectCollection goc = srcMG.get_grid_objects();
750 : CustomVertexGroup vrts;
751 :
752 : typedef typename Grid::traits<TElem>::iterator iter_t;
753 :
754 0 : for(iter_t eIter = goc.begin<TElem>(lvl); eIter != goc.end<TElem>(lvl); ++eIter)
755 : {
756 : TElem* e = *eIter;
757 0 : vrts.resize(e->num_vertices());
758 :
759 0 : for(size_t iv = 0; iv < e->num_vertices(); ++iv)
760 : {
761 0 : vrts.set_vertex(iv, aaNewVrt[e->vertex(iv)]);
762 : }
763 :
764 0 : TElem* ne = *destGrid.create_by_cloning(e, vrts);
765 0 : destSH.assign_subset(ne, srcSH.get_subset_index(e));
766 : }
767 0 : }
768 :
769 : template <class TAPos>
770 0 : void CopyGridLevel(MultiGrid& srcMG, Grid& destGrid,
771 : ISubsetHandler& srcSH, ISubsetHandler& destSH,
772 : int lvl, TAPos aPos)
773 : {
774 : Grid::VertexAttachmentAccessor<TAPos> aaPos(destGrid, aPos);
775 : Grid::VertexAttachmentAccessor<TAPos> aaSrcPos(srcMG, aPos);
776 0 : GridObjectCollection goc = srcMG.get_grid_objects();
777 :
778 : AVertex aNewVrt;
779 0 : srcMG.attach_to_vertices(aNewVrt);
780 : Grid::VertexAttachmentAccessor<AVertex> aaNewVrt(srcMG, aNewVrt);
781 :
782 0 : for(int si = destSH.num_subsets(); si < srcSH.num_subsets(); ++si)
783 : {
784 0 : destSH.subset_info(si) = srcSH.subset_info(si);
785 : }
786 :
787 0 : for(VertexIterator vrtIter = goc.begin<Vertex>(lvl); vrtIter != goc.end<Vertex>(lvl); ++vrtIter)
788 : {
789 : Vertex* srcVrt = *vrtIter;
790 0 : Vertex* destVrt = *destGrid.create_by_cloning(srcVrt);
791 :
792 0 : aaNewVrt[srcVrt] = destVrt;
793 : aaPos[destVrt] = aaSrcPos[srcVrt];
794 0 : destSH.assign_subset(destVrt, srcSH.get_subset_index(srcVrt));
795 : }
796 :
797 0 : CopyGridLevelElements<Edge>(srcMG, destGrid, srcSH, destSH, lvl, aNewVrt);
798 0 : CopyGridLevelElements<Face>(srcMG, destGrid, srcSH, destSH, lvl, aNewVrt);
799 0 : CopyGridLevelElements<Volume>(srcMG, destGrid, srcSH, destSH, lvl, aNewVrt);
800 :
801 : srcMG.detach_from_vertices(aNewVrt);
802 0 : }
803 :
804 : template <class TAPos>
805 0 : void CopyGrid(Grid& srcGrid, Grid& destGrid,
806 : ISubsetHandler& srcSH, ISubsetHandler& destSH,
807 : TAPos aPos)
808 : {
809 : Grid::VertexAttachmentAccessor<TAPos> aaPos(destGrid, aPos);
810 : Grid::VertexAttachmentAccessor<TAPos> aaSrcPos(srcGrid, aPos);
811 0 : GridObjectCollection goc = srcGrid.get_grid_objects();
812 :
813 : AVertex aNewVrt;
814 : srcGrid.attach_to_vertices(aNewVrt);
815 : Grid::VertexAttachmentAccessor<AVertex> aaNewVrt(srcGrid, aNewVrt);
816 :
817 0 : for(int si = destSH.num_subsets(); si < srcSH.num_subsets(); ++si)
818 : {
819 0 : destSH.subset_info(si) = srcSH.subset_info(si);
820 : }
821 :
822 0 : for(VertexIterator vrtIter = goc.begin<Vertex>(); vrtIter != goc.end<Vertex>(); ++vrtIter)
823 : {
824 : Vertex* srcVrt = *vrtIter;
825 0 : Vertex* destVrt = *destGrid.create_by_cloning(srcVrt);
826 0 : aaNewVrt[srcVrt] = destVrt;
827 : aaPos[destVrt] = aaSrcPos[srcVrt];
828 0 : destSH.assign_subset(destVrt, srcSH.get_subset_index(srcVrt));
829 : }
830 :
831 0 : CopyGridElements<Edge>(srcGrid, destGrid, srcSH, destSH, aNewVrt);
832 0 : CopyGridElements<Face>(srcGrid, destGrid, srcSH, destSH, aNewVrt);
833 0 : CopyGridElements<Volume>(srcGrid, destGrid, srcSH, destSH, aNewVrt);
834 :
835 : srcGrid.detach_from_vertices(aNewVrt);
836 0 : }
837 :
838 : template <class TAPos>
839 0 : bool SaveGridLevel(MultiGrid& srcMG, ISubsetHandler& srcSH,
840 : int lvl, const char* filename, TAPos aPos)
841 : {
842 0 : Grid destGrid;
843 0 : SubsetHandler destSH(destGrid);
844 :
845 0 : destGrid.attach_to_vertices(aPos);
846 :
847 0 : CopyGridLevel(srcMG, destGrid, srcSH, destSH, lvl, aPos);
848 0 : SaveGridToFile(destGrid, destSH, filename);
849 :
850 0 : return true;
851 0 : }
852 :
853 : template <typename TAPos>
854 0 : void MergeGrids
855 : (
856 : Grid& mrgGrid,
857 : Grid& grid,
858 : ISubsetHandler& mrgSH,
859 : ISubsetHandler& sh,
860 : TAPos aPos,
861 : bool joinSubsets
862 : )
863 : {
864 : // add offset to not join subsets with same index
865 0 : int subsetBaseInd = joinSubsets ? 0 : mrgSH.num_subsets();
866 :
867 : // attach data
868 : AVertex aVrt;
869 : grid.attach_to_vertices(aVrt);
870 :
871 : // attachments accessors for position and vertex index
872 0 : Grid::AttachmentAccessor<Vertex, TAPos> aaPosMRG(mrgGrid, aPos, true);
873 0 : Grid::AttachmentAccessor<Vertex, TAPos> aaPos(grid, aPos, true);
874 : Grid::AttachmentAccessor<Vertex, AVertex> aaVrt(grid, aVrt);
875 :
876 : // copy vertices
877 : for (VertexIterator iter = grid.begin<Vertex>();
878 0 : iter != grid.end<Vertex>(); ++iter)
879 : {
880 0 : Vertex* nvrt = *mrgGrid.create_by_cloning(*iter);
881 : aaPosMRG[nvrt] = aaPos[*iter];
882 0 : aaVrt[*iter] = nvrt;
883 0 : mrgSH.assign_subset(nvrt, subsetBaseInd + sh.get_subset_index(*iter));
884 : }
885 :
886 : // copy edges
887 0 : EdgeDescriptor ed;
888 : for (EdgeIterator iter = grid.begin<Edge>();
889 0 : iter != grid.end<Edge>(); ++iter)
890 : {
891 : Edge* eSrc = *iter;
892 0 : ed.set_vertices(aaVrt[eSrc->vertex(0)], aaVrt[eSrc->vertex(1)]);
893 0 : Edge* e = *mrgGrid.create_by_cloning(eSrc, ed);
894 0 : mrgSH.assign_subset(e, subsetBaseInd + sh.get_subset_index(eSrc));
895 : }
896 :
897 : // copy faces
898 0 : FaceDescriptor fd;
899 : for (FaceIterator iter = grid.begin<Face>();
900 0 : iter != grid.end<Face>(); ++iter)
901 : {
902 : Face* fSrc = *iter;
903 0 : fd.set_num_vertices((uint)fSrc->num_vertices());
904 0 : for (size_t i = 0; i < fd.num_vertices(); ++i) {
905 0 : fd.set_vertex((uint)i, aaVrt[fSrc->vertex(i)]);
906 : }
907 0 : Face* f = *mrgGrid.create_by_cloning(fSrc, fd);
908 0 : mrgSH.assign_subset(f, subsetBaseInd + sh.get_subset_index(fSrc));
909 : }
910 :
911 : // copy volumes
912 0 : VolumeDescriptor vd;
913 : for (VolumeIterator iter = grid.begin<Volume>();
914 0 : iter != grid.end<Volume>(); ++iter)
915 : {
916 : Volume* vSrc = *iter;
917 0 : vd.set_num_vertices((uint)vSrc->num_vertices());
918 0 : for (size_t i = 0; i < vd.num_vertices(); ++i) {
919 0 : vd.set_vertex((uint)i, aaVrt[vSrc->vertex(i)]);
920 : }
921 :
922 0 : Volume* v = *mrgGrid.create_by_cloning(vSrc, vd);
923 0 : mrgSH.assign_subset(v, subsetBaseInd + sh.get_subset_index(vSrc));
924 : }
925 :
926 : // remove the temporary attachment
927 : mrgGrid.detach_from_vertices(aVrt);
928 :
929 : // overwrite subset names
930 0 : for (int i_sub = 0; i_sub < sh.num_subsets(); ++i_sub){
931 0 : mrgSH.subset_info(subsetBaseInd + i_sub) = sh.subset_info(i_sub);
932 : }
933 0 : }
934 :
935 0 : bool SaveGridLevelToFile(MultiGrid& srcMG, ISubsetHandler& srcSH, int lvl, const char* filename)
936 : {
937 : // check whether one of the standard attachments is attached and call
938 : // SaveGridLevel with that attachment
939 : /*#ifdef UG_PARALLEL
940 : std::size_t found=filename.find(".ugx")
941 : if(found != string::npos){
942 : filename=filename.replace(found, 4, "");
943 : }
944 : filename=filename.append(std::to_string(pcl::ProRank()));
945 : if(found != string::npos){
946 : filename.append(".ugx");
947 : }
948 : #endif*/
949 0 : if(srcMG.has_vertex_attachment(aPosition))
950 0 : return SaveGridLevel(srcMG, srcSH, lvl, filename, aPosition);
951 0 : if(srcMG.has_vertex_attachment(aPosition2))
952 0 : return SaveGridLevel(srcMG, srcSH, lvl, filename, aPosition2);
953 0 : if(srcMG.has_vertex_attachment(aPosition1))
954 0 : return SaveGridLevel(srcMG, srcSH, lvl, filename, aPosition1);
955 :
956 : return false;
957 : }
958 :
959 : ////////////////////////////////////////////////////////////////////////////////
960 : ////////////////////////////////////////////////////////////////////////////////
961 : // explicit template instantiation
962 : template bool LoadGridFromFile(Grid&, ISubsetHandler&, const char*, AVector1&, int);
963 : template bool LoadGridFromFile(Grid&, ISubsetHandler&, const char*, AVector2&, int);
964 : template bool LoadGridFromFile(Grid&, ISubsetHandler&, const char*, AVector3&, int);
965 :
966 : template bool LoadGridFromFile(Grid&, const char*, AVector1&, int);
967 : template bool LoadGridFromFile(Grid&, const char*, AVector2&, int);
968 : template bool LoadGridFromFile(Grid&, const char*, AVector3&, int);
969 :
970 : template bool LoadGridFromFile(Grid&, SPProjectionHandler&, size_t&, ISubsetHandler&, std::vector<std::string>, std::vector<SmartPtr<ISubsetHandler>>, const char*, AVector1&, int);
971 : template bool LoadGridFromFile(Grid&, SPProjectionHandler&, size_t&, ISubsetHandler&, std::vector<std::string>, std::vector<SmartPtr<ISubsetHandler>>, const char*, AVector2&, int);
972 : template bool LoadGridFromFile(Grid&, SPProjectionHandler&, size_t&, ISubsetHandler&, std::vector<std::string>, std::vector<SmartPtr<ISubsetHandler>>, const char*, AVector3&, int);
973 :
974 : template bool SaveGridToFile(Grid&, ISubsetHandler&, const char*, AVector1&);
975 : template bool SaveGridToFile(Grid&, ISubsetHandler&, const char*, AVector2&);
976 : template bool SaveGridToFile(Grid&, ISubsetHandler&, const char*, AVector3&);
977 :
978 : template bool SaveGridToFile(Grid&, const char*, AVector1&);
979 : template bool SaveGridToFile(Grid&, const char*, AVector2&);
980 : template bool SaveGridToFile(Grid&, const char*, AVector3&);
981 :
982 : template void CopyGrid(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition1);
983 : template void CopyGrid(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition2);
984 : template void CopyGrid(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition3);
985 :
986 : template void MergeGrids(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition1, bool);
987 : template void MergeGrids(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition2, bool);
988 : template void MergeGrids(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition3, bool);
989 :
990 : }// end of namespace
|