File: bcfunctions.cpp

package info (click to toggle)
netgen 6.2.2601%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 13,076 kB
  • sloc: cpp: 166,627; tcl: 6,310; python: 2,868; sh: 522; makefile: 90
file content (458 lines) | stat: -rw-r--r-- 15,309 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458

#include <mystdlib.h>
#include <meshing.hpp>
#include "bcfunctions.hpp"


namespace netgen
{
   // Default colour to be used for boundary condition number "0"
   #define DEFAULT_R       0.0
   #define DEFAULT_G       1.0
   #define DEFAULT_B       0.0

   // Boundary condition number to use if a face does not have a 
   // colour assigned to it, or if the colour is the above defined 
   // default colour
   #define DEFAULT_BCNUM   1

   // Default tolerance for colour matching (using Euclidean distance)
   #define DEFAULT_EPS     2.5e-05




   /*! Philippose - 11/07/2009
       Function to check if two RGB colours are equal

       Note#1: Currently uses unweighted Euclidean Distance 
       for colour matching.

       Note#2: The tolerance used for deciding whether two 
       colours match is defined as "eps" and is currently 
       2.5e-5 (for square of distance)
   */
   bool ColourMatch(Vec<4> col1, Vec<4> col2, double eps)
   {
      if(eps <= 0.0) eps = DEFAULT_EPS;
      
      bool colmatch = false;

      if((col1-col2).Length2() < eps) colmatch = true;

      return colmatch;
   }
      




   /*! Philippose - 11/07/2009
       Function to create a list of all the unique colours 
       available in a given mesh
   */
  void GetFaceColours(Mesh & mesh, NgArray<Vec<4>> & face_colours)
   {
      face_colours.SetSize(1);
      face_colours.Elem(1) = mesh.GetFaceDescriptor(1).SurfColour();
      
      for(int i = 1; i <= mesh.GetNFD(); i++)
      {
         auto face_colour = mesh.GetFaceDescriptor(i).SurfColour();
         bool col_found = false;
         
         for(int j = 1; j <= face_colours.Size(); j++)
         {
            if(ColourMatch(face_colours.Elem(j),face_colour))
            {
               col_found = true;
               break;
            }
         }
         
         if(!col_found) face_colours.Append(face_colour);
      }

      if(printmessage_importance >= 3)
      {
         cout << endl << "-------- Face Colours --------" << endl;
         for( int i = 1; i <= face_colours.Size(); i++)
         {
            cout << face_colours.Elem(i) << endl;
         }
         cout << "------------------------------" << endl;
      }
   }






   /*! Philippose - 11/07/2009
       Assign boundary condition numbers based on a user defined 
       colour profile file.

       The default profile file is "netgen.ocf"

       If the mesh contains colours not defined in the profile,
       netgen automatically starts assigning each new colour a 
       new boundary condition number starting from the highest 
       boundary condition number specified in the profile file.
   */
   void AutoColourAlg_UserProfile(Mesh & mesh, ifstream & ocf)
   {
      char ocf_inp[100];
      bool header_found = false;

      // Number of colour specifications in the 
      // user profile file
      int numentries = 0;
      while((ocf.good()) && (!header_found))
      {
         ocf >> ocf_inp;
         if(strcmp(ocf_inp,"boundary_colours") == 0) header_found = true;
      }

      if(!header_found)
      {
         ocf.close();
         throw NgException("AutoColourAlg_UserProfile: Invalid or empty Boundary Colour Profile file\n");
         return;
      }

      // Read in the number of entries from file
      ocf >> numentries;
      if(numentries > 0)
      {
         if(!ocf.good())
         {
            ocf.close();
            throw NgException("AutoColourAlg_UserProfile: Invalid or empty Boundary Colour Profile file\n");
            return;
         }

         PrintMessage(3, "Number of colour entries: ", numentries);
      }
      else
      {
         ocf.close();
         PrintMessage(3, "AutoColourAlg_UserProfile: No Boundary Colour entries found.... no changes made!");
         return;
      }

      // Arrays to hold the specified RGB colour triplets as well 
      // as the associated boundary condition number
      NgArray<Vec<4>> bc_colours(numentries);
      NgArray<int> bc_num(numentries);
      NgArray<bool> bc_used(numentries);
      
      // Actually read in the data from the file
      for(int i = 1; i <= numentries; i++)
      {
         int bcnum;
         // double col_red, col_green, col_blue;

         ocf >> bcnum;
         // Boundary condition number DEFAULT_BCNUM is reserved for 
         // faces which have the default colour Green (0.0,1.0,0.0)
         // To prevent confusion, no boundary numbery below this default 
         // are permitted
         if(bcnum < (DEFAULT_BCNUM + 1)) bcnum = DEFAULT_BCNUM+1;

         bc_num.Elem(i) = bcnum;
         bc_used.Elem(i) = false;
         ocf >> bc_colours.Elem(i)[0]
             >> bc_colours.Elem(i)[1]
             >> bc_colours.Elem(i)[2];

         if(!ocf.good())
         {
            ocf.close();
            throw NgException("Boundary Colour file error: Number of entries do not match specified list size!!\n");
            return;
         }

         // Bound checking of the values
         // The RGB values should be between 0.0 and 1.0
         for(auto i : Range(3))
           bc_colours.Elem(bcnum)[i] = max2(min2(bc_colours.Elem(bcnum)[i], 1.), 0.);
      }

      PrintMessage(3, "Successfully loaded Boundary Colour Profile file....");
      ocf.close();

      // Find the highest boundary condition number in the list
      // All colours in the geometry which are not specified in the 
      // list will be given boundary condition numbers higher than this 
      // number
      int max_bcnum = DEFAULT_BCNUM;
      for(int i = 1; i <= bc_num.Size();i++)
      {
         if(bc_num.Elem(i) > max_bcnum) max_bcnum = bc_num.Elem(i);
      }

      PrintMessage(3, "Highest boundary number in list = ",max_bcnum);

      NgArray<Vec<4>> all_colours;
      
      // Extract all the colours to see how many there are
      GetFaceColours(mesh,all_colours);
      PrintMessage(3,"\nNumber of colours defined in Mesh: ", all_colours.Size());

      if(all_colours.Size() == 0)
      {
         PrintMessage(3,"No colour data detected in Mesh... no changes made!");
         return;
      }

      int nfd = mesh.GetNFD();

      for(int face_index = 1; face_index <= nfd; face_index++)
      {
         // Get the colour of the face being currently processed
         auto face_colour = mesh.GetFaceDescriptor(face_index).SurfColour();
         if(!ColourMatch(face_colour,Vec<4>(DEFAULT_R,DEFAULT_G,DEFAULT_B, 1.0)))
         {
            // Boolean variable to check if the boundary condition was applied 
            // or not... not applied would imply that the colour of the face 
            // does not exist in the list of colours in the profile file
            bool bc_assigned = false;

            for(int col_index = 1; col_index <= bc_colours.Size(); col_index++)
            {
               if((ColourMatch(face_colour,bc_colours.Elem(col_index))) && (!bc_assigned))
               {
                  mesh.GetFaceDescriptor(face_index).SetBCProperty(bc_num.Elem(col_index));
                  bc_used.Elem(col_index) = true;
                  bc_assigned = true;
                  break;
               }
            }

            // If the colour was not found in the list, add it to the list, and assign 
            // the next free boundary condition number to it
            if(!bc_assigned)
            {
               max_bcnum++;
               bc_num.Append(max_bcnum);
               bc_colours.Append(face_colour);
               bc_used.Append(true);

               mesh.GetFaceDescriptor(face_index).SetBCProperty(max_bcnum);
            }
         }
         else
         {
            // Set the boundary condition number to the default one
            mesh.GetFaceDescriptor(face_index).SetBCProperty(DEFAULT_BCNUM);
         }
      }

      // User Information of the results of the operation
      Vec<4> ref_colour(0.0,1.0,0.0,1.0);
      PrintMessage(3,"Colour based Boundary Condition Property details:");
      for(int bc_index = 0; bc_index <= bc_num.Size(); bc_index++)
      {
         if(bc_index > 0) ref_colour = bc_colours.Elem(bc_index);

         if(bc_index == 0) 
         {
            PrintMessage(3, "BC Property: ",DEFAULT_BCNUM);
            PrintMessage(3, "   RGB Face Colour = ",Vec3d{ref_colour[0], ref_colour[1], ref_colour[2]},"","\n");
         }
         else if(bc_used.Elem(bc_index))
         {
            PrintMessage(3, "BC Property: ",bc_num.Elem(bc_index));
            PrintMessage(3, "   RGB Face Colour = ",Vec3d{ref_colour[0], ref_colour[1], ref_colour[2]},"","\n");
         }
      }
   }




   
   /*! Philippose - 11/07/2009
       Assign boundary condition numbers based on the colours 
       assigned to each face in the mesh using an automated 
       algorithm.

       The particular algorithm used has been briefly explained 
       in the header file "occauxfunctions.hpp"
   */
   void AutoColourAlg_Sorted(Mesh & mesh)
   {
      NgArray<Vec<4>> all_colours;
      NgArray<int> faces_sorted;
      NgArray<int> colours_sorted;

      // Extract all the colours to see how many there are
      GetFaceColours(mesh,all_colours);

      // Delete the default colour from the list since it will be accounted 
      // for automatically
      for(int i = 1; i <= all_colours.Size(); i++)
      {
        if(ColourMatch(all_colours.Elem(i),Vec<4>(DEFAULT_R,DEFAULT_G,DEFAULT_B,1.0)))
         {
            all_colours.DeleteElement(i);
            break;
         }
      }
      PrintMessage(3,"\nNumber of colours defined in Mesh: ", all_colours.Size());

      if(all_colours.Size() == 0)
      {
         PrintMessage(3,"No colour data detected in Mesh... no changes made!");
         return;
      }

      // One more slot than the number of colours are required, to 
      // account for individual faces which have no colour data 
      // assigned to them in the CAD software
      faces_sorted.SetSize(all_colours.Size()+1);
      colours_sorted.SetSize(all_colours.Size()+1);
      faces_sorted = 0;
      
      // Index NgArray to identify the colours the faces were assigned to, 
      // after the bubble sort routine to sort the automatic boundary 
      // identifiers according to the number of surface mesh elements 
      // of a given colour
      for(int i = 0; i <= all_colours.Size(); i++) colours_sorted[i] = i;

      // Used to hold the number of surface elements without any OCC 
      // colour definition
      int no_colour_faces = 0;

      // Index in the faces array assigned to faces without any 
      // or the default colour definition
      int no_colour_index = 0;

      int nfd = mesh.GetNFD();

      // Extract the number of surface elements having a given colour
      // And save this number into an array for later sorting
      for(int face_index = 1; face_index <= nfd; face_index++)
        {
          Array<SurfaceElementIndex> se_face;
          
         mesh.GetSurfaceElementsOfFace(face_index, se_face);

         auto face_colour = mesh.GetFaceDescriptor(face_index).SurfColour();
         if(!ColourMatch(face_colour,Vec<4>(DEFAULT_R,DEFAULT_G,DEFAULT_B,1.0)))
         {
            for(int i = 1; i <= all_colours.Size(); i++)
            {
               if(ColourMatch(face_colour, all_colours.Elem(i)))
               {
                  faces_sorted[i] = faces_sorted[i] + se_face.Size();
               }
            }
         }
         else
         {
            // Add the number of surface elements without any colour 
            // definition separately
            no_colour_faces = no_colour_faces + se_face.Size();
         }
      }

      // Sort the face colour indices according to the number of surface 
      // mesh elements which have a specific colour
      BubbleSort(faces_sorted,colours_sorted);

      // Now update the array position assigned for surface elements 
      // without any colour definition with the number of elements
      faces_sorted[no_colour_index] = no_colour_faces;

      // Now actually assign the BC Property to the respective faces
      for(int face_index = 1; face_index <= nfd; face_index++)
      {
         auto face_colour = mesh.GetFaceDescriptor(face_index).SurfColour();
         if(!ColourMatch(face_colour,Vec<4>(DEFAULT_R,DEFAULT_G,DEFAULT_B, 1.0)))
         {
            for(int i = 0; i < colours_sorted.Size(); i++)
            {
               Vec<4> ref_colour;
               if(i != no_colour_index) ref_colour = all_colours.Elem(colours_sorted[i]);

               if(ColourMatch(face_colour, ref_colour))
               {
                  mesh.GetFaceDescriptor(face_index).SetBCProperty(i + DEFAULT_BCNUM);
               }
            }
         }
         else
         {
            mesh.GetFaceDescriptor(face_index).SetBCProperty(DEFAULT_BCNUM);
         }

         PrintMessage(4,"Face number: ",face_index," ; BC Property = ",mesh.GetFaceDescriptor(face_index).BCProperty());
      }

      // User Information of the results of the operation
      Vec<4> ref_colour(0.0,1.0,0.0,1.0);
      PrintMessage(3,"Colour based Boundary Condition Property details:");
      for(int i = 0; i < faces_sorted.Size(); i++)
      {
         if(colours_sorted[i] > 0) ref_colour = all_colours.Elem(colours_sorted[i]);

         PrintMessage(3, "BC Property: ",i + DEFAULT_BCNUM);
         PrintMessage(3, "   Nr. of Surface Elements = ", faces_sorted[i]);
         PrintMessage(3, "   Colour Index = ", colours_sorted[i]);
         PrintMessage(3, "   RGB Face Colour = ",Vec3d{ref_colour[0], ref_colour[1], ref_colour[2]},"","\n");
      }
   }





   /*! Philippose - 13/07/2009
       Main function implementing automated assignment of 
       Boundary Condition numbers based on face colours

       This functionality is currently implemtented at the mesh 
       level, and hence allows colour based assignment of boundary 
       conditions for any geometry type within netgen which 
       supports face colours
   */
   void AutoColourBcProps(Mesh & mesh, const char * bccolourfile)
   {
      // Go directly to the alternate algorithm if no colour profile file was specified
      if(!bccolourfile)
      {
         PrintMessage(1,"AutoColourBcProps: Using Automatic Colour based boundary property assignment algorithm");
         AutoColourAlg_Sorted(mesh);
      }
      else
      {
         ifstream ocf(bccolourfile);

         // If there was an error opening the Colour profile file, jump to the alternate 
         // algorithm after printing a message
         if(!ocf)
         {
            PrintMessage(1,"AutoColourBcProps: Error loading Boundary Colour Profile file ", 
                         bccolourfile, " ....","Switching to Automatic Assignment algorithm!");

            AutoColourAlg_Sorted(mesh);
         }
         // If the file opens successfully, call the function which assigns boundary conditions 
         // based on the colour profile file
         else
         {
            PrintMessage(1, "AutoColourBcProps: Using Boundary Colour Profile file: ");
            PrintMessage(1, "  ", bccolourfile);
            AutoColourAlg_UserProfile(mesh, ocf);

            // Make sure the file is closed before exiting the function
            if(ocf.is_open())
            {
               ocf.close();
            }
         }
      }
   }
}