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 : retVal = pcl::OneProcTrue(retVal, procCom);
308 : #endif
309 :
310 0 : return retVal;
311 : }
312 :
313 : ////////////////////////////////////////////////////////////////////////////////
314 : template <class TAPos>
315 0 : bool LoadGridFromFile(Grid& grid, SPProjectionHandler& ph, size_t& num_ph, ISubsetHandler& sh, vector<string> additionalSHNames,
316 : vector<SmartPtr<ISubsetHandler>> ash, const char* filename, TAPos& aPos, int procId)
317 : {
318 0 : return LoadGrid(grid, &ph, num_ph, &sh, additionalSHNames, ash, filename, aPos, procId);
319 : }
320 :
321 : template <class TAPos>
322 0 : bool LoadGridFromFile(Grid& grid, ISubsetHandler& sh,
323 : const char* filename, TAPos& aPos, int procId)
324 : {
325 0 : return LoadGrid(grid, &sh, filename, aPos, procId);
326 : }
327 :
328 : template <class TAPos>
329 0 : bool LoadGridFromFile(Grid& grid, const char* filename, TAPos& aPos, int procId)
330 : {
331 0 : return LoadGrid(grid, NULL, filename, aPos, procId);
332 : }
333 :
334 0 : bool LoadGridFromFile(Grid& grid, ISubsetHandler& sh, const char* filename, int procId)
335 : {
336 0 : return LoadGrid(grid, &sh, filename, aPosition, procId);
337 : }
338 :
339 0 : bool LoadGridFromFile(Grid& grid, const char* filename, int procId)
340 : {
341 0 : return LoadGrid(grid, NULL, filename, aPosition, procId);
342 : }
343 :
344 :
345 : ////////////////////////////////////////////////////////////////////////////////
346 : ////////////////////////////////////////////////////////////////////////////////
347 : // this method performs the actual save.
348 0 : static bool SaveGrid3d_IMPL(Grid& grid, ISubsetHandler* pSH,
349 : const char* filename, AVector3& aPos)
350 : {
351 0 : string strName = filename;
352 0 : if(strName.find(".txt") != string::npos)
353 0 : return SaveGridToTXT(grid, filename, aPos);
354 0 : if(strName.find(".2df") != string::npos)
355 0 : return SaveGridTo2DF(grid, filename, pSH, aPos);
356 0 : else if(strName.find(".obj") != string::npos)
357 0 : return SaveGridToOBJ(grid, filename, aPos, NULL, pSH);
358 0 : else if(strName.find(".lgb") != string::npos)
359 : {
360 : int numSHs = 0;
361 0 : if(pSH)
362 : numSHs = 1;
363 :
364 0 : return SaveGridToLGB(grid, filename, &pSH, numSHs, NULL, aPos);
365 : }
366 0 : else if(strName.find(".ele") != string::npos)
367 0 : return SaveGridToELE(grid, filename, pSH, aPos);
368 0 : else if(strName.find(".net") != string::npos)
369 0 : return SaveGridToART(grid, filename, pSH, aPos);
370 0 : else if(strName.find(".art") != string::npos)
371 0 : return SaveGridToART(grid, filename, pSH, aPos);
372 0 : else if(strName.find(".ncdf") != string::npos)
373 0 : return SaveGridToNCDF(grid, filename, pSH, aPos);
374 0 : else if(strName.find(".stl") != string::npos)
375 0 : return SaveGridToSTL(grid, filename, pSH, aPos);
376 0 : else if(strName.find(".smesh") != string::npos)
377 0 : return ExportGridToSMESH(grid, filename, aPos, pSH);
378 : else if((strName.find(".tikz") != string::npos)
379 0 : || (strName.find(".tex") != string::npos))
380 : {
381 0 : return ExportGridToTIKZ(grid, filename, pSH, aPos);
382 : }
383 0 : else if (strName.find(".swc") != string::npos)
384 0 : return ExportGridToSWC(grid, pSH, filename, aPos);
385 :
386 : return false;
387 : }
388 :
389 : ////////////////////////////////////////////////////////////////////////////////
390 0 : static bool SaveGrid3d(Grid& grid, ISubsetHandler* psh,
391 : const char* filename, APosition1& aPos)
392 : {
393 : APosition aPosTMP;
394 : grid.attach_to_vertices(aPosTMP);
395 : // convert the position data from the given dimension to 3d
396 0 : ConvertMathVectorAttachmentValues<Vertex>(grid, aPos, aPosTMP);
397 0 : if(SaveGrid3d_IMPL(grid, psh, filename, aPosTMP)){
398 : grid.detach_from_vertices(aPosTMP);
399 0 : return true;
400 : }
401 : grid.detach_from_vertices(aPosTMP);
402 : return false;
403 : }
404 :
405 : ////////////////////////////////////////////////////////////////////////////////
406 0 : static bool SaveGrid3d(Grid& grid, ISubsetHandler* psh,
407 : const char* filename, APosition2& aPos)
408 : {
409 : APosition aPosTMP;
410 : grid.attach_to_vertices(aPosTMP);
411 : // convert the position data from the given dimension to 3d
412 0 : ConvertMathVectorAttachmentValues<Vertex>(grid, aPos, aPosTMP);
413 0 : if(SaveGrid3d_IMPL(grid, psh, filename, aPosTMP)){
414 : grid.detach_from_vertices(aPosTMP);
415 0 : return true;
416 : }
417 : grid.detach_from_vertices(aPosTMP);
418 : return false;
419 : }
420 :
421 : ////////////////////////////////////////////////////////////////////////////////
422 : static bool SaveGrid3d(Grid& grid, ISubsetHandler* psh,
423 : const char* filename, APosition3& aPos)
424 : {
425 0 : return SaveGrid3d_IMPL(grid, psh, filename, aPos);
426 : }
427 :
428 : ////////////////////////////////////////////////////////////////////////////////
429 : template <class TAPos>
430 0 : static bool SaveGrid(Grid& grid, ISubsetHandler* psh,
431 : const char* filename, TAPos& aPos)
432 : {
433 0 : string strName = filename;
434 0 : if(strName.find(".ugx") != string::npos){
435 : #if (defined UG_PARALLEL && defined UG_DEBUG)
436 : std::size_t found=strName.find(".ugx");
437 : strName=strName.replace(found, 4, "");
438 : int procRank=pcl::ProcRank();
439 : strName=strName.append("_p");
440 : strName=strName.append(std::to_string(procRank));
441 : strName.append(".ugx");
442 : #endif
443 :
444 0 : if(psh)
445 0 : return SaveGridToUGX(grid, *psh, strName.c_str(), aPos);
446 : else {
447 0 : SubsetHandler shTmp(grid);
448 0 : return SaveGridToUGX(grid, shTmp, strName.c_str(), aPos);
449 0 : }
450 : }
451 0 : else if(strName.find(".vtu") != string::npos){
452 : #if (defined UG_PARALLEL && defined UG_DEBUG)
453 : std::size_t found=strName.find(".vtu");
454 : strName=strName.replace(found, 4, "");
455 : strName=strName.append("_p");
456 : strName=strName.append(std::to_string(pcl::ProcRank()));
457 : strName.append(".vtu");
458 : #endif
459 0 : return SaveGridToVTU(grid, psh, strName.c_str(), aPos);
460 : }
461 : else
462 0 : return SaveGrid3d(grid, psh, filename, aPos);
463 : }
464 :
465 :
466 : ////////////////////////////////////////////////////////////////////////////////
467 : template <class TAPos>
468 0 : bool SaveGridToFile(Grid& grid, ISubsetHandler& sh,
469 : const char* filename, TAPos& aPos)
470 : {
471 0 : return SaveGrid(grid, &sh, filename, aPos);
472 : }
473 :
474 : template <class TAPos>
475 0 : bool SaveGridToFile(Grid& grid, const char* filename, TAPos& aPos)
476 : {
477 0 : return SaveGrid(grid, NULL, filename, aPos);
478 : }
479 :
480 0 : bool SaveGridToFile(Grid& grid, ISubsetHandler& sh, const char* filename)
481 : {
482 : // check whether one of the standard attachments is attached and call
483 : // SaveGrid with that attachment
484 0 : if(grid.has_vertex_attachment(aPosition))
485 0 : return SaveGrid(grid, &sh, filename, aPosition);
486 0 : if(grid.has_vertex_attachment(aPosition2))
487 0 : return SaveGrid(grid, &sh, filename, aPosition2);
488 0 : if(grid.has_vertex_attachment(aPosition1))
489 0 : return SaveGrid(grid, &sh, filename, aPosition1);
490 :
491 : return false;
492 : }
493 :
494 0 : bool SaveGridToFile(Grid& grid, const char* filename)
495 : {
496 : // check whether one of the standard attachments is attached and call
497 : // SaveGrid with that attachment
498 0 : if(grid.has_vertex_attachment(aPosition))
499 0 : return SaveGrid(grid, NULL, filename, aPosition);
500 0 : if(grid.has_vertex_attachment(aPosition2))
501 0 : return SaveGrid(grid, NULL, filename, aPosition2);
502 0 : if(grid.has_vertex_attachment(aPosition1))
503 0 : return SaveGrid(grid, NULL, filename, aPosition1);
504 : return false;
505 : }
506 :
507 0 : bool SaveGridHierarchyTransformed(MultiGrid& mg, ISubsetHandler& sh,
508 : const char* filename, number offset)
509 : {
510 : PROFILE_FUNC_GROUP("grid");
511 : APosition aPos;
512 : // uses auto-attach
513 0 : Grid::AttachmentAccessor<Vertex, APosition> aaPos(mg, aPos, true);
514 :
515 : // copy the existing position to aPos. We take care of dimension differences.
516 : // Note: if the method was implemented for domains, this could be implemented
517 : // in a nicer way.
518 0 : if(mg.has_vertex_attachment(aPosition))
519 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition, aPos);
520 0 : else if(mg.has_vertex_attachment(aPosition2))
521 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition2, aPos);
522 0 : else if(mg.has_vertex_attachment(aPosition1))
523 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition1, aPos);
524 :
525 : // iterate through all vertices and apply an offset depending on their level.
526 0 : for(size_t lvl = 0; lvl < mg.num_levels(); ++lvl){
527 0 : for(VertexIterator iter = mg.begin<Vertex>(lvl);
528 0 : iter != mg.end<Vertex>(lvl); ++iter)
529 : {
530 0 : aaPos[*iter].z() += (number)lvl * offset;
531 : }
532 : }
533 :
534 : // finally save the grid
535 : bool writeSuccess = SaveGridToFile(mg, sh, filename, aPos);
536 :
537 : // clean up
538 : mg.detach_from_vertices(aPos);
539 :
540 0 : return writeSuccess;
541 : }
542 :
543 0 : bool SaveGridHierarchyTransformed(MultiGrid& mg, const char* filename,
544 : number offset)
545 : {
546 : PROFILE_FUNC_GROUP("grid");
547 : // cast away constness
548 : SubsetHandler& sh = mg.get_hierarchy_handler();
549 :
550 : APosition aPos;
551 : // uses auto-attach
552 0 : Grid::AttachmentAccessor<Vertex, APosition> aaPos(mg, aPos, true);
553 :
554 : // copy the existing position to aPos. We take care of dimension differences.
555 : // Note: if the method was implemented for domains, this could be implemented
556 : // in a nicer way.
557 0 : if(mg.has_vertex_attachment(aPosition))
558 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition, aPos);
559 0 : else if(mg.has_vertex_attachment(aPosition2))
560 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition2, aPos);
561 0 : else if(mg.has_vertex_attachment(aPosition1))
562 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition1, aPos);
563 :
564 : // iterate through all vertices and apply an offset depending on their level.
565 0 : for(size_t lvl = 0; lvl < mg.num_levels(); ++lvl){
566 0 : for(VertexIterator iter = mg.begin<Vertex>(lvl);
567 0 : iter != mg.end<Vertex>(lvl); ++iter)
568 : {
569 0 : aaPos[*iter].z() += (number)lvl * offset;
570 : }
571 : }
572 :
573 : // finally save the grid
574 0 : bool writeSuccess = SaveGridToFile(mg, sh, filename, aPos);
575 :
576 : // clean up
577 : mg.detach_from_vertices(aPos);
578 :
579 0 : return writeSuccess;
580 : }
581 :
582 : template <class TElem>
583 0 : static void AssignSubsetsByInterfaceType(SubsetHandler& sh, MultiGrid& mg)
584 : {
585 : const int siNormal = 0;
586 : const int siHMaster = 1;
587 : const int siHSlave = 1 << 1;
588 : const int siVMaster = 1 << 2;
589 : const int siVSlave = 1 << 3;
590 :
591 0 : const char* subsetNames[] = {"normal", "hmaster", "hslave", "hslave+hmaster",
592 : "vmaster", "vmaster+hmaster", "vmaster+hslave",
593 : "vmaster+hslave+hmaster", "vslave", "vslave+hmaster",
594 : "vslave+hslave", "vslave+hslave+hmaster",
595 : "vslave+vmaster", "vslave+vmaster+hmaster",
596 : "vslave+vmaster+hslave", "vslave+vmaster+hmaster+hslave"};
597 :
598 0 : for(int i = 0; i < 16; ++i)
599 0 : sh.subset_info(i).name = subsetNames[i];
600 :
601 : typedef typename Grid::traits<TElem>::iterator TIter;
602 0 : for(TIter iter = mg.begin<TElem>(); iter != mg.end<TElem>(); ++iter){
603 : int status = ES_NONE;
604 :
605 : #ifdef UG_PARALLEL
606 : DistributedGridManager* distGridMgr = mg.distributed_grid_manager();
607 : if(distGridMgr)
608 : status = distGridMgr->get_status(*iter);
609 : #endif
610 :
611 : int index = siNormal;
612 : if(status & ES_H_MASTER)
613 : index |= siHMaster;
614 : if(status & ES_H_SLAVE)
615 : index |= siHSlave;
616 : if(status & ES_V_MASTER)
617 : index |= siVMaster;
618 : if(status & ES_V_SLAVE)
619 : index |= siVSlave;
620 :
621 0 : sh.assign_subset(*iter, index);
622 : }
623 0 : }
624 :
625 0 : bool SaveParallelGridLayout(MultiGrid& mg, const char* filename, number offset)
626 : {
627 : PROFILE_FUNC_GROUP("grid");
628 :
629 : APosition aPos;
630 : // uses auto-attach
631 0 : Grid::AttachmentAccessor<Vertex, APosition> aaPos(mg, aPos, true);
632 :
633 : // copy the existing position to aPos. We take care of dimension differences.
634 : // Note: if the method was implemented for domains, this could be implemented
635 : // in a nicer way.
636 0 : if(mg.has_vertex_attachment(aPosition))
637 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition, aPos);
638 0 : else if(mg.has_vertex_attachment(aPosition2))
639 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition2, aPos);
640 0 : else if(mg.has_vertex_attachment(aPosition1))
641 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition1, aPos);
642 :
643 : // iterate through all vertices and apply an offset depending on their level.
644 0 : for(size_t lvl = 0; lvl < mg.num_levels(); ++lvl){
645 0 : for(VertexIterator iter = mg.begin<Vertex>(lvl);
646 0 : iter != mg.end<Vertex>(lvl); ++iter)
647 : {
648 0 : aaPos[*iter].z() += (number)lvl * offset;
649 : }
650 : }
651 :
652 : // create a subset handler which holds different subsets for the different interface types
653 0 : SubsetHandler sh(mg);
654 :
655 0 : AssignSubsetsByInterfaceType<Vertex>(sh, mg);
656 0 : AssignSubsetsByInterfaceType<Edge>(sh, mg);
657 0 : AssignSubsetsByInterfaceType<Face>(sh, mg);
658 0 : AssignSubsetsByInterfaceType<Volume>(sh, mg);
659 :
660 0 : AssignSubsetColors(sh);
661 0 : EraseEmptySubsets(sh);
662 :
663 : // finally save the grid
664 : bool writeSuccess = SaveGridToFile(mg, sh, filename, aPos);
665 :
666 : // clean up
667 : mg.detach_from_vertices(aPos);
668 :
669 0 : return writeSuccess;
670 0 : }
671 :
672 : template <class TElem>
673 0 : static void AssignSubsetsBySurfaceViewState(SubsetHandler& sh, const SurfaceView& sv,
674 : MultiGrid& mg)
675 : {
676 : typedef typename Grid::traits<TElem>::iterator TIter;
677 0 : for(TIter iter = mg.begin<TElem>(); iter != mg.end<TElem>(); ++iter){
678 : TElem* e = *iter;
679 :
680 0 : sh.assign_subset(e, sv.surface_state(e).get());
681 : }
682 0 : for(int i = 0; i < sh.num_subsets(); ++i)
683 0 : sh.subset_info(i).name = "unknown";
684 0 : sh.subset_info(SurfaceView::MG_SHADOW_PURE).name = "shadow-pure";
685 0 : sh.subset_info(SurfaceView::MG_SURFACE_PURE).name = "surface-pure";
686 0 : sh.subset_info(SurfaceView::MG_SURFACE_RIM).name = "surface-rim";
687 0 : sh.subset_info(SurfaceView::MG_SHADOW_RIM_COPY).name = "shadow-rim-copy";
688 0 : sh.subset_info(SurfaceView::MG_SHADOW_RIM_NONCOPY).name = "shadow-rim-noncopy";
689 : //EraseEmptySubsets(sh);
690 0 : }
691 :
692 0 : bool SaveSurfaceViewTransformed(MultiGrid& mg, const SurfaceView& sv,
693 : const char* filename, number offset)
694 : {
695 : PROFILE_FUNC_GROUP("grid");
696 :
697 : APosition aPos;
698 : // uses auto-attach
699 0 : Grid::AttachmentAccessor<Vertex, APosition> aaPos(mg, aPos, true);
700 :
701 : // copy the existing position to aPos. We take care of dimension differences.
702 : // Note: if the method was implemented for domains, this could be implemented
703 : // in a nicer way.
704 0 : if(mg.has_vertex_attachment(aPosition))
705 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition, aPos);
706 0 : else if(mg.has_vertex_attachment(aPosition2))
707 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition2, aPos);
708 0 : else if(mg.has_vertex_attachment(aPosition1))
709 0 : ConvertMathVectorAttachmentValues<Vertex>(mg, aPosition1, aPos);
710 :
711 : // iterate through all vertices and apply an offset depending on their level.
712 0 : for(size_t lvl = 0; lvl < mg.num_levels(); ++lvl){
713 0 : for(VertexIterator iter = mg.begin<Vertex>(lvl);
714 0 : iter != mg.end<Vertex>(lvl); ++iter)
715 : {
716 0 : aaPos[*iter].z() += (number)lvl * offset;
717 : }
718 : }
719 :
720 : // create a subset handler which holds different subsets for the different interface types
721 0 : SubsetHandler sh(mg);
722 :
723 0 : AssignSubsetsBySurfaceViewState<Vertex>(sh, sv, mg);
724 0 : AssignSubsetsBySurfaceViewState<Edge>(sh, sv, mg);
725 0 : AssignSubsetsBySurfaceViewState<Face>(sh, sv, mg);
726 0 : AssignSubsetsBySurfaceViewState<Volume>(sh, sv, mg);
727 :
728 0 : AssignSubsetColors(sh);
729 0 : EraseEmptySubsets(sh);
730 :
731 : // finally save the grid
732 : bool writeSuccess = SaveGridToFile(mg, sh, filename, aPos);
733 :
734 : // clean up
735 : mg.detach_from_vertices(aPos);
736 :
737 0 : return writeSuccess;
738 0 : }
739 :
740 : template<class TElem>
741 0 : void CopyGridLevelElements(MultiGrid& srcMG, Grid& destGrid,
742 : ISubsetHandler& srcSH, ISubsetHandler& destSH,
743 : int lvl, AVertex& aNewVrt)
744 : {
745 : Grid::VertexAttachmentAccessor<AVertex> aaNewVrt(srcMG, aNewVrt);
746 0 : GridObjectCollection goc = srcMG.get_grid_objects();
747 : CustomVertexGroup vrts;
748 :
749 : typedef typename Grid::traits<TElem>::iterator iter_t;
750 :
751 0 : for(iter_t eIter = goc.begin<TElem>(lvl); eIter != goc.end<TElem>(lvl); ++eIter)
752 : {
753 : TElem* e = *eIter;
754 0 : vrts.resize(e->num_vertices());
755 :
756 0 : for(size_t iv = 0; iv < e->num_vertices(); ++iv)
757 : {
758 0 : vrts.set_vertex(iv, aaNewVrt[e->vertex(iv)]);
759 : }
760 :
761 0 : TElem* ne = *destGrid.create_by_cloning(e, vrts);
762 0 : destSH.assign_subset(ne, srcSH.get_subset_index(e));
763 : }
764 0 : }
765 :
766 : template <class TAPos>
767 0 : void CopyGridLevel(MultiGrid& srcMG, Grid& destGrid,
768 : ISubsetHandler& srcSH, ISubsetHandler& destSH,
769 : int lvl, TAPos aPos)
770 : {
771 : Grid::VertexAttachmentAccessor<TAPos> aaPos(destGrid, aPos);
772 : Grid::VertexAttachmentAccessor<TAPos> aaSrcPos(srcMG, aPos);
773 0 : GridObjectCollection goc = srcMG.get_grid_objects();
774 :
775 : AVertex aNewVrt;
776 0 : srcMG.attach_to_vertices(aNewVrt);
777 : Grid::VertexAttachmentAccessor<AVertex> aaNewVrt(srcMG, aNewVrt);
778 :
779 0 : for(int si = destSH.num_subsets(); si < srcSH.num_subsets(); ++si)
780 : {
781 0 : destSH.subset_info(si) = srcSH.subset_info(si);
782 : }
783 :
784 0 : for(VertexIterator vrtIter = goc.begin<Vertex>(lvl); vrtIter != goc.end<Vertex>(lvl); ++vrtIter)
785 : {
786 : Vertex* srcVrt = *vrtIter;
787 0 : Vertex* destVrt = *destGrid.create_by_cloning(srcVrt);
788 :
789 0 : aaNewVrt[srcVrt] = destVrt;
790 : aaPos[destVrt] = aaSrcPos[srcVrt];
791 0 : destSH.assign_subset(destVrt, srcSH.get_subset_index(srcVrt));
792 : }
793 :
794 0 : CopyGridLevelElements<Edge>(srcMG, destGrid, srcSH, destSH, lvl, aNewVrt);
795 0 : CopyGridLevelElements<Face>(srcMG, destGrid, srcSH, destSH, lvl, aNewVrt);
796 0 : CopyGridLevelElements<Volume>(srcMG, destGrid, srcSH, destSH, lvl, aNewVrt);
797 :
798 : srcMG.detach_from_vertices(aNewVrt);
799 0 : }
800 :
801 : template <class TAPos>
802 0 : void CopyGrid(Grid& srcGrid, Grid& destGrid,
803 : ISubsetHandler& srcSH, ISubsetHandler& destSH,
804 : TAPos aPos)
805 : {
806 : Grid::VertexAttachmentAccessor<TAPos> aaPos(destGrid, aPos);
807 : Grid::VertexAttachmentAccessor<TAPos> aaSrcPos(srcGrid, aPos);
808 0 : GridObjectCollection goc = srcGrid.get_grid_objects();
809 :
810 : AVertex aNewVrt;
811 : srcGrid.attach_to_vertices(aNewVrt);
812 : Grid::VertexAttachmentAccessor<AVertex> aaNewVrt(srcGrid, aNewVrt);
813 :
814 0 : for(int si = destSH.num_subsets(); si < srcSH.num_subsets(); ++si)
815 : {
816 0 : destSH.subset_info(si) = srcSH.subset_info(si);
817 : }
818 :
819 0 : for(VertexIterator vrtIter = goc.begin<Vertex>(); vrtIter != goc.end<Vertex>(); ++vrtIter)
820 : {
821 : Vertex* srcVrt = *vrtIter;
822 0 : Vertex* destVrt = *destGrid.create_by_cloning(srcVrt);
823 0 : aaNewVrt[srcVrt] = destVrt;
824 : aaPos[destVrt] = aaSrcPos[srcVrt];
825 0 : destSH.assign_subset(destVrt, srcSH.get_subset_index(srcVrt));
826 : }
827 :
828 0 : CopyGridElements<Edge>(srcGrid, destGrid, srcSH, destSH, aNewVrt);
829 0 : CopyGridElements<Face>(srcGrid, destGrid, srcSH, destSH, aNewVrt);
830 0 : CopyGridElements<Volume>(srcGrid, destGrid, srcSH, destSH, aNewVrt);
831 :
832 : srcGrid.detach_from_vertices(aNewVrt);
833 0 : }
834 :
835 : template <class TAPos>
836 0 : bool SaveGridLevel(MultiGrid& srcMG, ISubsetHandler& srcSH,
837 : int lvl, const char* filename, TAPos aPos)
838 : {
839 0 : Grid destGrid;
840 0 : SubsetHandler destSH(destGrid);
841 :
842 0 : destGrid.attach_to_vertices(aPos);
843 :
844 0 : CopyGridLevel(srcMG, destGrid, srcSH, destSH, lvl, aPos);
845 0 : SaveGridToFile(destGrid, destSH, filename);
846 :
847 0 : return true;
848 0 : }
849 :
850 : template <typename TAPos>
851 0 : void MergeGrids
852 : (
853 : Grid& mrgGrid,
854 : Grid& grid,
855 : ISubsetHandler& mrgSH,
856 : ISubsetHandler& sh,
857 : TAPos aPos,
858 : bool joinSubsets
859 : )
860 : {
861 : // add offset to not join subsets with same index
862 0 : int subsetBaseInd = joinSubsets ? 0 : mrgSH.num_subsets();
863 :
864 : // attach data
865 : AVertex aVrt;
866 : grid.attach_to_vertices(aVrt);
867 :
868 : // attachments accessors for position and vertex index
869 0 : Grid::AttachmentAccessor<Vertex, TAPos> aaPosMRG(mrgGrid, aPos, true);
870 0 : Grid::AttachmentAccessor<Vertex, TAPos> aaPos(grid, aPos, true);
871 : Grid::AttachmentAccessor<Vertex, AVertex> aaVrt(grid, aVrt);
872 :
873 : // copy vertices
874 : for (VertexIterator iter = grid.begin<Vertex>();
875 0 : iter != grid.end<Vertex>(); ++iter)
876 : {
877 0 : Vertex* nvrt = *mrgGrid.create_by_cloning(*iter);
878 : aaPosMRG[nvrt] = aaPos[*iter];
879 0 : aaVrt[*iter] = nvrt;
880 0 : mrgSH.assign_subset(nvrt, subsetBaseInd + sh.get_subset_index(*iter));
881 : }
882 :
883 : // copy edges
884 0 : EdgeDescriptor ed;
885 : for (EdgeIterator iter = grid.begin<Edge>();
886 0 : iter != grid.end<Edge>(); ++iter)
887 : {
888 : Edge* eSrc = *iter;
889 0 : ed.set_vertices(aaVrt[eSrc->vertex(0)], aaVrt[eSrc->vertex(1)]);
890 0 : Edge* e = *mrgGrid.create_by_cloning(eSrc, ed);
891 0 : mrgSH.assign_subset(e, subsetBaseInd + sh.get_subset_index(eSrc));
892 : }
893 :
894 : // copy faces
895 0 : FaceDescriptor fd;
896 : for (FaceIterator iter = grid.begin<Face>();
897 0 : iter != grid.end<Face>(); ++iter)
898 : {
899 : Face* fSrc = *iter;
900 0 : fd.set_num_vertices((uint)fSrc->num_vertices());
901 0 : for (size_t i = 0; i < fd.num_vertices(); ++i) {
902 0 : fd.set_vertex((uint)i, aaVrt[fSrc->vertex(i)]);
903 : }
904 0 : Face* f = *mrgGrid.create_by_cloning(fSrc, fd);
905 0 : mrgSH.assign_subset(f, subsetBaseInd + sh.get_subset_index(fSrc));
906 : }
907 :
908 : // copy volumes
909 0 : VolumeDescriptor vd;
910 : for (VolumeIterator iter = grid.begin<Volume>();
911 0 : iter != grid.end<Volume>(); ++iter)
912 : {
913 : Volume* vSrc = *iter;
914 0 : vd.set_num_vertices((uint)vSrc->num_vertices());
915 0 : for (size_t i = 0; i < vd.num_vertices(); ++i) {
916 0 : vd.set_vertex((uint)i, aaVrt[vSrc->vertex(i)]);
917 : }
918 :
919 0 : Volume* v = *mrgGrid.create_by_cloning(vSrc, vd);
920 0 : mrgSH.assign_subset(v, subsetBaseInd + sh.get_subset_index(vSrc));
921 : }
922 :
923 : // remove the temporary attachment
924 : mrgGrid.detach_from_vertices(aVrt);
925 :
926 : // overwrite subset names
927 0 : for (int i_sub = 0; i_sub < sh.num_subsets(); ++i_sub){
928 0 : mrgSH.subset_info(subsetBaseInd + i_sub) = sh.subset_info(i_sub);
929 : }
930 0 : }
931 :
932 0 : bool SaveGridLevelToFile(MultiGrid& srcMG, ISubsetHandler& srcSH, int lvl, const char* filename)
933 : {
934 : // check whether one of the standard attachments is attached and call
935 : // SaveGridLevel with that attachment
936 : /*#ifdef UG_PARALLEL
937 : std::size_t found=filename.find(".ugx")
938 : if(found != string::npos){
939 : filename=filename.replace(found, 4, "");
940 : }
941 : filename=filename.append(std::to_string(pcl::ProRank()));
942 : if(found != string::npos){
943 : filename.append(".ugx");
944 : }
945 : #endif*/
946 0 : if(srcMG.has_vertex_attachment(aPosition))
947 0 : return SaveGridLevel(srcMG, srcSH, lvl, filename, aPosition);
948 0 : if(srcMG.has_vertex_attachment(aPosition2))
949 0 : return SaveGridLevel(srcMG, srcSH, lvl, filename, aPosition2);
950 0 : if(srcMG.has_vertex_attachment(aPosition1))
951 0 : return SaveGridLevel(srcMG, srcSH, lvl, filename, aPosition1);
952 :
953 : return false;
954 : }
955 :
956 : ////////////////////////////////////////////////////////////////////////////////
957 : ////////////////////////////////////////////////////////////////////////////////
958 : // explicit template instantiation
959 : template bool LoadGridFromFile(Grid&, ISubsetHandler&, const char*, AVector1&, int);
960 : template bool LoadGridFromFile(Grid&, ISubsetHandler&, const char*, AVector2&, int);
961 : template bool LoadGridFromFile(Grid&, ISubsetHandler&, const char*, AVector3&, int);
962 :
963 : template bool LoadGridFromFile(Grid&, const char*, AVector1&, int);
964 : template bool LoadGridFromFile(Grid&, const char*, AVector2&, int);
965 : template bool LoadGridFromFile(Grid&, const char*, AVector3&, int);
966 :
967 : template bool LoadGridFromFile(Grid&, SPProjectionHandler&, size_t&, ISubsetHandler&, std::vector<std::string>, std::vector<SmartPtr<ISubsetHandler>>, const char*, AVector1&, int);
968 : template bool LoadGridFromFile(Grid&, SPProjectionHandler&, size_t&, ISubsetHandler&, std::vector<std::string>, std::vector<SmartPtr<ISubsetHandler>>, const char*, AVector2&, int);
969 : template bool LoadGridFromFile(Grid&, SPProjectionHandler&, size_t&, ISubsetHandler&, std::vector<std::string>, std::vector<SmartPtr<ISubsetHandler>>, const char*, AVector3&, int);
970 :
971 : template bool SaveGridToFile(Grid&, ISubsetHandler&, const char*, AVector1&);
972 : template bool SaveGridToFile(Grid&, ISubsetHandler&, const char*, AVector2&);
973 : template bool SaveGridToFile(Grid&, ISubsetHandler&, const char*, AVector3&);
974 :
975 : template bool SaveGridToFile(Grid&, const char*, AVector1&);
976 : template bool SaveGridToFile(Grid&, const char*, AVector2&);
977 : template bool SaveGridToFile(Grid&, const char*, AVector3&);
978 :
979 : template void CopyGrid(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition1);
980 : template void CopyGrid(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition2);
981 : template void CopyGrid(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition3);
982 :
983 : template void MergeGrids(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition1, bool);
984 : template void MergeGrids(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition2, bool);
985 : template void MergeGrids(Grid&, Grid&, ISubsetHandler&, ISubsetHandler&, APosition3, bool);
986 :
987 : }// end of namespace
|