DFNgen  2.0
DFN Model Generator
DFNmain.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <random>
3 #include <algorithm>
4 #include <iterator> // std::copy
5 #include <iomanip>
6 #include "structures.h"
7 #include "insertShape.h"
8 #include <vector>
9 #include "input.h"
10 #include "output.h"
11 #include "readInputFunctions.h"
12 #include "clusterGroups.h"
13 #include "mathFunctions.h"
14 #include "domain.h"
15 #include "computationalGeometry.h"
16 #include "generatingPoints.h"
17 #include "distributions.h"
18 #include "fractureEstimating.h"
19 #include "debugFunctions.h"
20 #include "removeFractures.h"
21 
22 // Used for automated python testing
23 #include "testing.h"
24 
25 // Below includes are used for hotkey,
26 // Stops inserting fractures and goes directly to output
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <sys/select.h>
31 #include <termios.h>
32 #include "hotkey.h"
33 
34 
35 // DO NOT CHANGE VAR NAME
36 struct termios orig_termios; //used for custom console and hotkey
37 
38 // Global eps
39 double eps;
40 
41 // SEE STRUCTURES.H FOR ALL STRUCTURE DEFINITIONS
42 int main (int argc, char **argv) {
43  std::cout << "\n";
44 
45  // Error check on cmd line input:
46  // 1st argument = input file path
47  // 2nd argument = output folder path
48  if (argc != 3) {
49  if (argc == 1 ) {
50  std::cout << "ERROR: DFNWorks input and output file "
51  << "paths were not included on command line.\n";
52  return 1;
53  }
54  else if (argc == 2) {
55  std::cout << "ERROR: DFNWorks output file path "
56  << "was not included on command line.\n";
57  return 1;
58  }
59  }
60 
61 /************* Initialize Arrays/Vectors and Structures **************/
62 
63  // Vector to store accepted polygons/fractures
64  std::vector<Poly> acceptedPoly;
65  acceptedPoly.reserve(500);
66 
67  // Vector for storing intersections
68  std::vector<IntPoints> intPts;
69  intPts.reserve(250);
70 
71  // Vector for storing triple intersection points
72  std::vector<Point> triplePoints;
73 
74  // Vector for shape families/ stochastic families
75  std::vector<Shape> shapeFamilies;
76 
77  // Statistics structure:
78  // Keeps track of DFN statistics (see definition in structures.h)
79  Stats pstats;
80 
81 /*********************************************************************/
82 
83  // Read Input File
84  // Initialize input variables. Most input variables are global
85  getInput(argv[1], shapeFamilies);
86 
87  // Set epsilon
88  eps = h * 1e-8;
89 
90  std::cout << "\nh: " << h << "\n";
91 
92  int totalFamilies = nFamEll + nFamRect;
93 
94  // Print shape families to screen
95  if (totalFamilies > 0) {
96  printShapeFams(shapeFamilies);
97  }
98 
99  // Initialize random generator with seed ( see c++ <random> )
100  // Mersene Twister 19937 generator (64 bit)
101  if (seed == 0) {
103  }
104  std::mt19937_64 generator(seed);
105 
106  // Init distributions class
107  // Currenlty used only for exponential distribution
108  Distributions distributions(generator, shapeFamilies);
109 
110  float domVol = domainSize[0]*domainSize[1]*domainSize[2];
111 
112  if (totalFamilies > 0 ) {
113 
114  if (stopCondition == 0) { // Npoly Option
115  // Estimate fractures, generate radii lists for nPoly option
116  generateRadiiLists_nPolyOption(shapeFamilies, famProb, generator, distributions);
117  }
118  else { // P32 Option
119  // ESTIMATE # FRACTURES NEEDED
120  if (disableFram == false) {
121  std::cout << "\nEstimating number of fractures needed...\n";
122  dryRun(shapeFamilies, famProb, generator, distributions);
123  }
124  }
125 
126  // Add a percentage more radii to each radii
127  // list using families' distribution.
128  // First arg is percentage, eg: 0.1 will add 10% more fractures
129  // to the radii list for each family
130  if (disableFram == false) {
131  addRadiiToLists(radiiListIncrease, shapeFamilies, generator, distributions);
132 
133  for (unsigned int j = 0; j < shapeFamilies.size(); j++) {
134 
135  if (shapeFamilies[j].distributionType == 4) {
136  // Constant size
137  std::cout << shapeType(shapeFamilies[j])
138  << " family " << getFamilyNumber(j,shapeFamilies[j].shapeFamily)
139  << " using constant size\n";
140  }
141  else {
142  std::cout << "Estimated " << shapeFamilies[j].radiiList.size()
143  << " fractures for " << shapeType(shapeFamilies[j])
144  << " family " << getFamilyNumber(j,shapeFamilies[j].shapeFamily)
145  << "\n";
146  }
147  }
148  sortRadii(shapeFamilies);
149  }
150  // Keep count of accepted & rejected fractures by family
151  pstats.acceptedFromFam = new int[totalFamilies];
152  pstats.rejectedFromFam = new int[totalFamilies];
153 
154  // Save sizes of pre-generated radii lists per family.
155  // Print as part of statistics to user
156  pstats.expectedFromFam = new int[totalFamilies];
157 
158  // Zero arrays, init expectedFromFam array
159  for (int i = 0; i < totalFamilies; i++) {
160  pstats.acceptedFromFam[i] = 0;
161  pstats.rejectedFromFam[i] = 0;
162  pstats.expectedFromFam[i] = shapeFamilies[i].radiiList.size();
163  }
164  // Init first rejects per insertion attempt counter
165  pstats.rejectsPerAttempt.push_back(0);
166 
167  }
168 
169  /*********** SETUP HOT KEY *************/
170  char key = 0;
171  #ifndef TESTING
172  // Set custom terminal settings for hotkey functionality
174  atexit(reset_terminal_mode);
175  #endif
176  /********* END SETUP HOT KEY **********/
177 
178  /********************* User Defined Shapes Insertion ************************/
179 
180  if (insertUserRectanglesFirst == 1) {
181  // Insert user rects first
182  if (userRectanglesOnOff != 0) {
183  insertUserRects(acceptedPoly, intPts, pstats, triplePoints);
184  }
185  // Insert all user rectangles by coordinates
186  if (userRecByCoord !=0 ) {
187  insertUserRectsByCoord(acceptedPoly, intPts, pstats, triplePoints);
188  }
189  // Insert all user ellipses
190  if (userEllipsesOnOff != 0) {
191  insertUserEll(acceptedPoly, intPts, pstats, triplePoints);
192  }
193  // Insert all user ellipses by coordinates
194  if (userEllByCoord != 0) {
195  insertUserEllByCoord(acceptedPoly, intPts, pstats, triplePoints);
196  }
197  }
198 
199  else {
200  // Insert all user ellipses first
201  if (userEllipsesOnOff != 0) {
202  insertUserEll(acceptedPoly, intPts, pstats, triplePoints);
203  }
204  // Insert all user ellipses by coordinates
205  if (userEllByCoord != 0) {
206  insertUserEllByCoord(acceptedPoly, intPts, pstats, triplePoints);
207  }
208  // Insert user rects
209  if (userRectanglesOnOff != 0) {
210  insertUserRects(acceptedPoly, intPts, pstats, triplePoints);
211  }
212  // Insert all user rectangles by coordinates
213  if (userRecByCoord !=0 ) {
214  insertUserRectsByCoord(acceptedPoly, intPts, pstats, triplePoints);
215  }
216  }
217 
218  /********* Probabilities (famProb) setup, CDF init *****************/
219 
220  // 'CDF' size will shrink along when used with fracture intensity (P32) option
221  float *CDF;
222  int cdfSize = totalFamilies;
223 
224  if (totalFamilies > 0) {
225  // Convert famProb to CDF
226  CDF = createCDF(famProb, cdfSize);
227  }
228 
229  std::ofstream radiiAll;
230  std::string output = argv[2];
231  std::string radiiFolder = output + "/radii";
232 
233  // Create output folder if not already created
234  //makeDIR(argv[2]);
235 
236  // Create radii folder
237  //makeDIR(radiiFolder.c_str());
238 
239  // Create polys folder
240  std::string polyFolder = output + "/polys";
241  //makeDIR(polyFolder.c_str());
242 
243  if (outputAllRadii == 1) {
244  // Option to include all radii in output (accepted and rejected)
245  std::string file = radiiFolder + "/radii_All.dat";
246  radiiAll.open(file.c_str(), std::ofstream::out | std::ofstream::trunc);
247  radiiAll << "Format: xRadius yRadius Family# (-1 = userRectangle, 0 = userEllipse, > 0 is family in order of famProb)\n";
248  }
249 
250  // Initialize uniform distribution on [0,1]
251  std::uniform_real_distribution<double> uniformDist(0,1);
252 
253  if (totalFamilies > 0) {
254 
255  // Holds index to current 'shapeFamily' being inserted
256  int familyIndex;
257 
258  /******************************************************************************************/
259  /************************** MAIN LOOP ******************************/
260 
261  // NOTE: p32Complete() works on global array 'p32Status'
262  // p32Complete() only needs argument of the number of defined shape families
263  // ********* Begin stochastic fracture insertion ***********
264  while (((stopCondition == 0 && pstats.acceptedPolyCount < nPoly) || (stopCondition == 1 && p32Complete(totalFamilies) == 0)) && key != '~' ) {
265 
266  // cdfIdx holds the index to the CDF array for the current shape family being inserted
267  int cdfIdx;
268 
269  if (stopCondition == 0 ) { // nPoly Option
270  // Choose a family based purely on famProb probabilities
271  familyIndex = indexFromProb(CDF, uniformDist(generator), totalFamilies);
272  }
273 
274  // Choose a family based on probabiliyis AND their target p32 completion status.
275  // If a family has already met is fracture intinisty req. (p32) don't choose that family anymore
276  else { // P32 Option
277  familyIndex = indexFromProb_and_P32Status(CDF, uniformDist(generator), totalFamilies, cdfSize, cdfIdx);
278  }
279 
280  struct Poly newPoly = generatePoly(shapeFamilies[familyIndex], generator, distributions, familyIndex, true);
281 
282  if (outputAllRadii == 1) {
283  // Output all radii
284  radiiAll << std::setprecision(8) << newPoly.xradius << " " << newPoly.yradius
285  << " " << newPoly.familyNum + 1 << "\n";
286  }
287 
288  int rejectCode = 1;
289  int rejectCounter = 0;
290 
291  while (rejectCode != 0) { // Loop used to reinsert same poly with different translation
292 
293  // HOT KEY: check for keyboard input
294  if (kbhit()) {
295  key = getch();
296  }
297 
298  // Truncate poly if needed
299  // Reutnrs 1 if poly is outside of domain or has less than 3 vertices
300  if ( domainTruncation(newPoly, domainSize) == 1) {
301  // Poly was completely outside domain, or was truncated to less than
302  // 3 vertices due to vertices being too close together
303  pstats.rejectionReasons.outside++;
304  // Test if newPoly has reached its limit of insertion attempts
305  if (rejectCounter >= rejectsPerFracture) {
306  delete[] newPoly.vertices; // Created with new, delete manually
307  rejectCounter++;
308  break; // Reject poly, generate new polygon
309  }
310  else { // Retranslate poly and try again, preserving normal, size, and shape
311  reTranslatePoly(newPoly, shapeFamilies[familyIndex], generator);
312  continue; // Go to next iteration of while loop, test new translation
313  }
314  }
315 
316  // Create/assign bounding box
317  createBoundingBox(newPoly);
318 
319  // Find line of intersection and FRAM check
320  rejectCode = intersectionChecking(newPoly, acceptedPoly, intPts, pstats, triplePoints);
321  #ifdef TESTING
322  if (rejectCode != 0) {
323  return 1;
324  }
325  #endif
326 
327  // IF POLY ACCEPTED:
328  if(rejectCode == 0) { // Intersections are ok
329  // Incriment counter of accepted polys
330  pstats.acceptedPolyCount++;
331  pstats.acceptedFromFam[familyIndex]++;
332 
333  // Make new rejection counter for next fracture attempt
334  pstats.rejectsPerAttempt.push_back(0);
335 
336  if (newPoly.truncated == 1) {
337  pstats.truncated++;
338  }
339 
340  // Calculate poly's area
341  newPoly.area = getArea(newPoly);
342 
343  // Update P32
344  if (shapeFamilies[familyIndex].layer == 0) { // Whole domain
345  shapeFamilies[familyIndex].currentP32 += newPoly.area*2/domVol;
346  }
347  else { // Layer
348  shapeFamilies[familyIndex].currentP32 += newPoly.area*2/layerVol[shapeFamilies[familyIndex].layer-1];
349  }
350 
351  if (stopCondition == 1) {
352  // If the last inserted pologon met the p32 reqirement, set that familiy to no longer
353  // insert any more fractures. ajust the CDF and familiy probabilites to account for this
354  if (shapeFamilies[familyIndex].currentP32 >= shapeFamilies[familyIndex].p32Target ) {
355 
356  p32Status[familyIndex] = 1; // Mark family as having its p32 requirement met
357  std::cout << "\nP32 For Family " << familyIndex+1 << " Completed\n\n";
358 
359  // Adjust CDF, PDF. Reduce their size by 1.
360  // Remove the completed family's element in 'CDF[]' and 'famProb[]'
361  // Distribute the removed family probability evenly among the others and rebuild the CDF
362  // familyIndex = index of family's probability
363  // cdfIdx = index of the completed family's correspongding CDF index
364  if (cdfSize > 1 ) { // If there are still more families to insert
365  // Remove completed family from CDF and famProb
366  adjustCDF_and_famProb(CDF, famProb, cdfSize, cdfIdx);
367  }
368  }
369  }
370 
371 
372  // Output to user: print running program status to user
373  if (pstats.acceptedPolyCount % 200 == 0) {
374  std::cout << "\nAccepted " << pstats.acceptedPolyCount << " fractures\n";
375  std::cout << "Rejected " << pstats.rejectedPolyCount << " fractures\n";
376  std::cout << "Re-translated " << pstats.retranslatedPolyCount << " fractures\n\n";
377 
378  std::cout << "Current p32 values per family:\n";
379  for (int i = 0; i < totalFamilies; i++) {
380 
381  if (stopCondition == 0) {
382  std::cout << shapeType(shapeFamilies[i]) << " family "
383  << getFamilyNumber(i,shapeFamilies[i].shapeFamily)
384  << " Current P32 = " << std::setprecision(8)
385  << shapeFamilies[i].currentP32;
386  }
387  else {
388  std::cout << shapeType(shapeFamilies[i]) << " family "
389  << getFamilyNumber(i,shapeFamilies[i].shapeFamily)
390  << " target P32 = " << std::setprecision(8)
391  << shapeFamilies[i].p32Target
392  << ", " << "Current P32 = " << shapeFamilies[i].currentP32;
393  }
394 
395  if (stopCondition == 1 && shapeFamilies[i].p32Target <= shapeFamilies[i].currentP32) {
396  std::cout << "...Done\n";
397  }
398  else {
399  std::cout << "\n";
400  }
401  }
402  }
403 
404  // SAVING POLYGON (intersection and triple points saved witchin intersectionChecking())
405  acceptedPoly.push_back(newPoly); // SAVE newPoly to accepted polys list
406 
407  }
408 
409  else { // Poly rejected
410 
411  // Inc reject counter for current poly
412  rejectCounter++;
413 
414  // Inc reject counter for current attempt
415  // (number of rejects until next fracture accepted)
416  pstats.rejectsPerAttempt[pstats.acceptedPolyCount]++;
417 
418 
419  if (printRejectReasons != 0) {
420  printRejectReason(rejectCode, newPoly);
421  }
422 
423  if (rejectCounter >= rejectsPerFracture) {
424  delete[] newPoly.vertices; // Delete manually, created with new[]
425  pstats.rejectedPolyCount++;
426  pstats.rejectedFromFam[familyIndex]++;
427  // Stop retranslating polygon if its reached its reject limit
428  break; // Break will cause code to go to next poly
429  }
430  else {
431  // Translate poly to new position
432  if (printRejectReasons != 0) {
433  std::cout << "Translating rejected fracture to new position\n";
434  }
435  pstats.retranslatedPolyCount++;
436  reTranslatePoly(newPoly, shapeFamilies[familyIndex], generator);
437  }
438  } // End else poly rejected
439  } // End loop while for re-translating polys option (reject == 1)
440  } // !!!! END MAIN LOOP !!!! end while loop for inserting polyons
441 
442  // Remove last element off the rejects per attempt counter.
443  // It will have one extra item due to how eachelement is initialized.
444  if (!pstats.rejectsPerAttempt.empty()) {
445  pstats.rejectsPerAttempt.pop_back();
446  }
447 
448  } // End if totalFamilies != 0
449 
450  /************************** DFN GENERATION IS COMPLETE ***************************/
451 // printIntersectionData(intPts);
452 // printGroupData(pstats,acceptedPoly);
453 
454  // The close to node check is inside of the close to edge check function
455  // for optimization (only need do intersection close to node on one condition)
456  // On close to node rejections, close to edge is counted as well.
457  // To get the correct number we must subtract the close to node count
458  // (they were counted in closeToEdge AND closeToNode)
460 
461 
462 
463  #ifndef TESTING
465  #endif
466 
467  if (outputAllRadii == 1) {
468  radiiAll.close();
469  }
470 
471  // Assign apertures and permiability to accepted polygons
472  for (unsigned int i = 0; i < acceptedPoly.size(); i++) {
473  assignAperture(acceptedPoly[i], generator);
474  // NOTE: must assign aperture before permeability
475  assignPermeability(acceptedPoly[i]);
476  }
477 
478  // Copy end of DFN generation stats to file, as well as print to screen
479  std::ofstream file;
480  std::string fileName = output + "/DFN_output.txt";
481  file.open(fileName.c_str(), std::ofstream::out | std::ofstream::trunc);
482  file << "\n========================================================\n";
483  file << " Network Generation Complete\n";
484  file << "========================================================\n";
485 
486 
487  std::cout << "\n========================================================\n";
488  std::cout << " Network Generation Complete\n";
489  std::cout << "========================================================\n";
490 
491 
492  if (stopCondition == 1 ) {
493  std::cout << "\nFinal p32 values per family:\n";
494  for (int i = 0; i < totalFamilies; i++) {
495  std::cout << "Family " << i+1 << " target P32 = " << shapeFamilies[i].p32Target
496  << ", " << "Final P32 = " << shapeFamilies[i].currentP32 << "\n";
497  file << "Family " << i+1 << " target P32 = " << shapeFamilies[i].p32Target
498  << ", " << "Final P32 = " << shapeFamilies[i].currentP32 << "\n";
499  }
500 
501  }
502 
503  std::cout << "\n________________________________________________________\n";
504  file << "\n________________________________________________________\n";
505 
506  // Calculate total area, volume
507  double userDefinedShapesArea = 0;
508  double userDefinedVol = 0;
509  double *familyArea = nullptr;
510  double *familyVol = nullptr;
511  if (totalFamilies > 0 ) {
512  familyArea = new double[totalFamilies]; // Holds fracture area per family
513  familyVol = new double[totalFamilies];
514 
515  // Zero array
516  for (int i = 0; i < totalFamilies; i++) {
517  familyArea[i] = 0;
518  familyVol[i] = 0;
519  }
520 
521  }
522 
523  std::cout << "\nStatistics Before Isolated Fractures Removed:\n\n";
524  std::cout << "Fractures: " << acceptedPoly.size() << "\n";
525  std::cout << "Truncated: " << pstats.truncated << "\n\n";
526 
527  file << "\nStatistics Before Isolated Fractures Removed:\n\n";
528  file << "Fractures: " << acceptedPoly.size() << "\n";
529  file << "Truncated: " << pstats.truncated << "\n\n";
530 
531  // Calculate total fracture area, and area per family
532  for (unsigned int i = 0; i < acceptedPoly.size(); i++) {
533  double area = acceptedPoly[i].area;
534  double vol = area * acceptedPoly[i].aperture;
535 
536  pstats.areaBeforeRemoval += area;
537  pstats.volBeforeRemoval += vol;
538 
539  if (acceptedPoly[i].familyNum >= 0) {
540  familyArea[acceptedPoly[i].familyNum] += area;
541  familyVol[acceptedPoly[i].familyNum] += vol;
542  }
543  else { // User-defined polygon
544  userDefinedShapesArea += area;
545  userDefinedVol += vol;
546  }
547  }
548 
549  std::cout << "Total Surface Area: " << pstats.areaBeforeRemoval * 2 << " m^2\n";
550  std::cout << "Total Fractures Volume: " << pstats.volBeforeRemoval << " m^3\n";
551  std::cout << "Total Fracture Density (P30): " <<acceptedPoly.size()/domVol << "\n";
552  std::cout << "Total Fracture Intensity (P32): " << (pstats.areaBeforeRemoval * 2)/domVol << "\n";
553  std::cout << "Total Fracture Porosity (P33): " << pstats.volBeforeRemoval/domVol << "\n\n";
554 
555  file << "Total Surface Area: " << pstats.areaBeforeRemoval * 2 << " m^2\n";
556  file << "Total Fractures Volume: " << pstats.volBeforeRemoval << " m^3\n";
557  file << "Total Fracture Density (P30): " <<acceptedPoly.size()/domVol << "\n";
558  file << "Total Fracture Intensity (P32): " << (pstats.areaBeforeRemoval * 2)/domVol << "\n";
559  file << "Total Fracture Porosity (P33): " << pstats.volBeforeRemoval/domVol << "\n\n";
560 
561  // Print family stats to user
562  for (int i = 0; i < totalFamilies; i++) {
563  std::cout << "Family " << i+1 << ":\n";
564  std::cout << " Accepted: " << pstats.acceptedFromFam[i] << "\n";
565  std::cout << " Rejected: " << pstats.rejectedFromFam[i] << "\n";
566 
567  file << "Family " << i+1 << ":\n";
568  file << " Accepted: " << pstats.acceptedFromFam[i] << "\n";
569  file << " Rejected: " << pstats.rejectedFromFam[i] << "\n";
570 
571  if ( shapeFamilies[i].layer > 0) {
572  int idx = (shapeFamilies[i].layer-1)*2;
573  std::cout << " Layer: " << shapeFamilies[i].layer << "\n";
574  std::cout << " Layer {-z, +z}: {" <<layers[idx]<< ", " <<layers[idx+1]<< "}\n";
575  file << " Layer: " << shapeFamilies[i].layer << "\n";
576  file << " Layer {-z, +z}: {" <<layers[idx]<< ", " <<layers[idx+1]<< "}\n";
577  }
578  else {
579  std::cout << " Layer: Whole Domain \n";
580  file << " Layer: Whole Domain \n";
581  }
582  std::cout << " Surface Area: " << familyArea[i]*2 << " m^2\n";
583  std::cout << " Volume: " << familyVol[i] << " m^3\n";
584  std::cout << " Fracture Intensity (P32): " << shapeFamilies[i].currentP32 << "\n\n";
585 
586  file << " Surface Area: " << familyArea[i]*2 << " m^2\n";
587  file << " Volume: " << familyVol[i] << " m^3\n";
588  file << " Fracture Intensity (P32): " << shapeFamilies[i].currentP32 << "\n\n";
589 
590  }
591 
592  if (userDefinedShapesArea > 0) {
593  std::cout << "User Defined: \n";
594  std::cout << " Surface Area: " << userDefinedShapesArea*2 << " m^2\n";
595  std::cout << " Volume: " << userDefinedVol << " m^3\n";
596  std::cout << " Fracture Intensity (P32): " << userDefinedShapesArea*2/domVol << "\n\n";
597 
598  file << "User Defined: \n";
599  file << " Surface Area: " << userDefinedShapesArea*2 << " m^2\n";
600  file << " Volume: " << userDefinedVol << " m^3\n";
601  file << " Fracture Intensity (P32): " << userDefinedShapesArea*2/domVol << "\n\n";
602 
603  }
604 
605 
606  if (removeFracturesLessThan > 0) {
607  std::cout << "\nRemoving fractures with radius less than " << removeFracturesLessThan << " and rebuilding DFN\n";
608  file << "\nRemoving fractures with radius less than " << removeFracturesLessThan << " and rebuilding DFN\n";
609  int size = acceptedPoly.size();
610  removeFractures(removeFracturesLessThan, acceptedPoly, intPts, triplePoints, pstats);
611 
612  std::cout << "Removed " << size - acceptedPoly.size() << " fractures with radius less than " << removeFracturesLessThan << "\n\n";
613  file << "Removed " << size - acceptedPoly.size() << " fractures with radius less than " << removeFracturesLessThan << "\n\n";
614  }
615 
616 
617 for (int i = 0; i < acceptedPoly.size(); i++) {
618  printPolyData(acceptedPoly[i]);
619  std::cout << "\n";
620 
621 }
622 
623 
624 
625 /* Remove any isolated fractures and return
626  a list of polygon indices matching the users
627  boundaryFaces option. If input option
628  keepOnlyLargestCluster = 1, return largest
629  cluster matching users boundaryFaces option
630  If ignoreBoundaryFaces input option is on,
631  DFN will keep all fractures with intersections.
632 */
633  std::vector<unsigned int> finalFractures = getCluster(pstats);
634  // Sort fracture indecies to retain order by acceptance
635  std::sort (finalFractures.begin(), finalFractures.end());
636 
637  // Error check for no boundary connection
638  bool printConnectivityError = 0;
639  if (finalFractures.size() == 0 && ignoreBoundaryFaces == 0 ) {
640  printConnectivityError = 1;
641  //if there is no fracture network connected useres liststed boundary faces
642  //switch to ignore boundary faces option with notice to user that there is no connectivity
643  ignoreBoundaryFaces = 1; // NOW EXITING
644  finalFractures = getCluster(pstats);
645  //if still no fractures, there is no fracture network
646  }
647 
648  if (finalFractures.size() == 0) {
649  std::cout << "\nERROR: DFN Generation has finished, however"
650  << " there are no intersecting fractures."
651  << " Please adjust input parameters.\n";
652  std::cout << "Try increasing the fracture density, or shrinking the domain.\n";
653 
654  file << "\nERROR: DFN Generation has finished, however"
655  << " there are no intersecting fractures."
656  << " Please adjust input parameters.\n";
657  file << "Try increasing the fracture density, or shrinking the domain.\n";
658  file.close();
659  exit(1);
660  }
661 
662  /************************* Print Statistics to User ***********************************/
663 
664  std::cout << "\n________________________________________________________\n\n";
665  std::cout << "Statistics After Isolated Fractures Removed:\n";
666  std::cout << "Final Number of Fractures: " << finalFractures.size() << "\n";
667  std::cout << "Isolated Fractures Removed: " << acceptedPoly.size() - finalFractures.size() << "\n";
668  std::cout << "Fractures before isolated fractures removed:: " << acceptedPoly.size() << "\n\n";
669 
670  file << "\n________________________________________________________\n\n";
671  file << "Statistics After Isolated Fractures Removed:\n";
672  file << "Final Number of Fractures: " << finalFractures.size() << "\n";
673  file << "Isolated Fractures Removed: " << acceptedPoly.size() - finalFractures.size() << "\n";
674  file << "Fractures before isolated fractures removed:: " << acceptedPoly.size() << "\n\n";
675 
676 
677  // Reset totalVolume and totalArea to 0
678  userDefinedShapesArea = 0;
679  userDefinedVol = 0;
680 
681  if (totalFamilies > 0 ) {
682  //zero out array.
683  for (int i = 0; i < totalFamilies; i++) {
684  familyArea[i] = 0;
685  familyVol[i] = 0;
686  }
687  }
688 
689 
690  // Calculate total fracture area, and area per family
691  for (unsigned int i = 0; i < finalFractures.size(); i++) {
692  double area = acceptedPoly[finalFractures[i]].area;
693  double vol = area * acceptedPoly[finalFractures[i]].aperture;
694 
695  pstats.areaAfterRemoval += area;
696  pstats.volAfterRemoval += vol;
697 
698  if (acceptedPoly[finalFractures[i]].familyNum >= 0) {
699  familyArea[acceptedPoly[finalFractures[i]].familyNum] += area;
700  familyVol[acceptedPoly[finalFractures[i]].familyNum] += vol;
701  }
702  else { // User-defined polygon
703  userDefinedShapesArea += area;
704  userDefinedVol += vol;
705  }
706  }
707 
708  // Re-count number of accepted fracture per family after isloated fractures were removed
709  int *acceptedFromFamCounters = nullptr;
710  if (totalFamilies > 0) {
711  acceptedFromFamCounters = new int[totalFamilies];
712 
713  for (int i = 0; i < totalFamilies; i++) {
714  // zero counters
715  acceptedFromFamCounters[i] = 0;
716  }
717 
718  int size = finalFractures.size();
719  for (int i = 0; i < size; i++) {
720  if (acceptedPoly[finalFractures[i]].familyNum >= 0) {
721  acceptedFromFamCounters[acceptedPoly[finalFractures[i]].familyNum]++;
722  }
723  }
724  }
725 
726  std::cout << "Total Surface Area: " << pstats.areaAfterRemoval * 2 << " m^2\n";
727  std::cout << "Total Fractures Volume: " << pstats.volAfterRemoval << " m^3\n";
728  std::cout << "Total Fracture Density (P30): " << finalFractures.size()/domVol << "\n";
729  std::cout << "Total Fracture Intensity (P32): " << (pstats.areaAfterRemoval * 2)/domVol << "\n";
730  std::cout << "Total Fracture Porosity (P33): " << pstats.volAfterRemoval/domVol << "\n\n";
731 
732  file << "Total Surface Area: " << pstats.areaAfterRemoval * 2 << " m^2\n";
733  file << "Total Fractures Volume: " << pstats.volAfterRemoval << " m^3\n";
734  file << "Total Fracture Density (P30): " << finalFractures.size()/domVol << "\n";
735  file << "Total Fracture Intensity (P32): " << (pstats.areaAfterRemoval * 2)/domVol << "\n";
736  file << "Total Fracture Porosity (P33): " << pstats.volAfterRemoval/domVol << "\n\n";
737 
738  // Print family stats to user
739  for (int i = 0; i < totalFamilies; i++) {
740 
741  std::cout << "Family " << i+1 << ":\n";
742  std::cout << " Fractures After Isloated Fracture Removal: " << acceptedFromFamCounters[i] << "\n";
743  std::cout << " Isolated Fractures Removed: " << pstats.acceptedFromFam[i] - acceptedFromFamCounters[i] << "\n";
744  std::cout << " Accepted: " << pstats.acceptedFromFam[i] << "\n";
745  std::cout << " Rejected: " << pstats.rejectedFromFam[i] << "\n";
746 
747  file << "Family " << i+1 << ":\n";
748  file << " Fractures After Isloated Fracture Removal: " << acceptedFromFamCounters[i] << "\n";
749  file << " Isolated Fractures Removed: " << pstats.acceptedFromFam[i] - acceptedFromFamCounters[i] << "\n";
750  file << " Accepted: " << pstats.acceptedFromFam[i] << "\n";
751  file << " Rejected: " << pstats.rejectedFromFam[i] << "\n";
752 
753  if ( shapeFamilies[i].layer > 0) {
754  int idx = (shapeFamilies[i].layer-1)*2;
755  std::cout << " Layer: " << shapeFamilies[i].layer << "\n";
756  std::cout << " Layer {-z, +z}: {" <<layers[idx]<< "," <<layers[idx+1]<< "}\n";
757 
758  file << " Layer: " << shapeFamilies[i].layer << "\n";
759  file << " Layer {-z, +z}: {" <<layers[idx]<< "," <<layers[idx+1]<< "}\n";
760  }
761  else {
762  std::cout << " Layer: Whole Domain \n";
763  file << " Layer: Whole Domain \n";
764  }
765  std::cout << " Surface Area: " << familyArea[i]*2 << " m^2\n";
766  std::cout << " Volume: " << familyVol[i] << " m^3\n";
767  std::cout << " Fracture Intesnsity (P32): " << familyArea[i]*2/domVol << "\n\n";
768 
769  file << " Surface Area: " << familyArea[i]*2 << " m^2\n";
770  file << " Volume: " << familyVol[i] << " m^3\n";
771  file << " Fracture Intesnsity (P32): " << familyArea[i]*2/domVol << "\n\n";
772  }
773 
774  if (userDefinedShapesArea > 0) {
775  std::cout << "User Defined Shapes: \n";
776  std::cout << " Surface Area: " << userDefinedShapesArea*2 << " m^2\n";
777  std::cout << " Volume: " << userDefinedVol << " m^3\n";
778  std::cout << " Fracture Intensity (P32): " << userDefinedShapesArea*2/domVol << "\n\n";
779 
780  file << "User Defined Shapes: \n";
781  file << " Surface Area: " << userDefinedShapesArea*2 << " m^2\n";
782  file << " Volume: " << userDefinedVol << " m^3\n";
783  file << " Fracture Intensity (P32): " << userDefinedShapesArea*2/domVol << "\n\n";
784  }
785 
786  if (acceptedFromFamCounters != nullptr) {
787  delete[] acceptedFromFamCounters;
788  }
789 
790  std::cout << "\n________________________________________________________\n\n";
791  file << "\n________________________________________________________\n\n";
792 
793  std::cout << "\n" << acceptedPoly.size()<< " Fractures Accepted (Before Isolated Fracture Removal)\n";
794  std::cout << finalFractures.size()<< " Final Fractures (After Isolated Fracture Removal)\n\n";
795  std::cout << "Total Fractures Rejected: " << pstats.rejectedPolyCount << "\n";
796  std::cout << "Total Fractures Re-translated: " << pstats.retranslatedPolyCount << "\n";
797 
798  file << "\n" << acceptedPoly.size()<< " Fractures Accepted (Before Isolated Fracture Removal)\n";
799  file << finalFractures.size()<< " Final Fractures (After Isolated Fracture Removal)\n\n";
800  file << "Total Fractures Rejected: " << pstats.rejectedPolyCount << "\n";
801  file << "Total Fractures Re-translated: " << pstats.retranslatedPolyCount << "\n";
802 
803  if (printConnectivityError == 1) {
804  std::cout << "\nERROR: DFN generation has finished but the formed\n"
805  << "fracture network does not make a connection between\n"
806  << "the user's specifed boundary faces.\n";
807  std::cout << "Try increasing the fracture density, shrinking the domain\n"
808  << "or consider using the 'ignoreBoundaryFaces' option.\n";
809 
810  file << "\nERROR: DFN generation has finished but the formed\n"
811  << "fracture network does not make a connection between\n"
812  << "the user's specifed boundary faces.\n";
813  file << "Try increasing the fracture density, shrinking the domain\n"
814  << "or consider using the 'ignoreBoundaryFaces' option.\n";
815 
816  file.close();
817  exit(1);
818  }
819 
820  //************ Intersection Stats ***************
821  std::cout << "\nNumber of Triple Intersection Points (Before Isolated Fracture Removal): " << triplePoints.size() << "\n";
822  file << "\nNumber of Triple Intersection Points (Before Isolated Fracture Removal): " << triplePoints.size() << "\n";
823  // Shrink intersection stats
824  std::cout << "\nIntersection Statistics:\n";
825  std::cout << " " << pstats.intersectionsShortened << " of " << intPts.size() << " Intersections Shortened\n";
826  std::cout << " Original Intersection (Before Intersection Shrinking) Length: " << pstats.originalLength << "m\n";
827  std::cout << " Intersection Length Discarded: " << pstats.discardedLength << "m\n";
828  std::cout << " Final Intersection Length: " << pstats.originalLength - pstats.discardedLength << "m\n";
829 
830  file << "\nIntersection Statistics:\n";
831  file << " " << pstats.intersectionsShortened << " of " << intPts.size() << " Intersections Shortened\n";
832  file << " Original Intersection (Before Intersection Shrinking) Length: " << pstats.originalLength << "m\n";
833  file << " Intersection Length Discarded: " << pstats.discardedLength << "m\n";
834  file << " Final Intersection Length: " << pstats.originalLength - pstats.discardedLength << "m\n";
835 
836  //*********** Rejection Stats *******************
837  std::cout << "\nRejection Statistics: \n";
838  std::cout << " " << pstats.rejectionReasons.shortIntersection << " Short Intersections \n";
839  std::cout << " " << pstats.rejectionReasons.closeToNode << " Close to Node\n";
840  std::cout << " " << pstats.rejectionReasons.closeToEdge << " Close to Edge\n";
841  std::cout << " " << pstats.rejectionReasons.closePointToEdge << " Vertice Close to Edge\n";
842  std::cout << " " << pstats.rejectionReasons.outside << " Outside of Domain\n";
843  std::cout << " " << pstats.rejectionReasons.triple << " Triple intersection Rejections\n";
844  std::cout << " " << pstats.rejectionReasons.interCloseToInter << " Intersections Close to Other Intersections\n\n";
845 
846  file << "\nRejection Statistics: \n";
847  file << " " << pstats.rejectionReasons.shortIntersection << " Short Intersections \n";
848  file << " " << pstats.rejectionReasons.closeToNode << " Close to Node\n";
849  file << " " << pstats.rejectionReasons.closeToEdge << " Close to Edge\n";
850  file << " " << pstats.rejectionReasons.closePointToEdge << " Vertice Close to Edge\n";
851  file << " " << pstats.rejectionReasons.outside << " Outside of Domain\n";
852  file << " " << pstats.rejectionReasons.triple << " Triple intersection Rejections\n";
853  file << " " << pstats.rejectionReasons.interCloseToInter << " Intersections Close to Other Intersections\n\n";
854 
855 
856  std::cout << "\n________________________________________________________\n\n";
857  file << "\n________________________________________________________\n\n";
858 
859  if (totalFamilies > 0) {
860 
861  std::cout << "Fracture Estimation statistics:\n";
862  file << "Fracture Estimation statistics:\n";
863 
864  std::cout << "NOTE: If estimation and actual are very different, \nexpected family distributions might "
865  << "not be accurate. \nIf this is the case, try increasing or decreasing \nthe 'radiiListIncrease' option "
866  << "in the input file.\n\n";
867  file << "NOTE: If estimation and actual are very different, \nexpected family distributions might "
868  << "not be accurate. \nIf this is the case, try increasing or decreasing \nthe 'radiiListIncrease' option "
869  << "in the input file.\n\n";
870 
871  // Compare expected radii/poly size and actual
872  for (int i = 0; i < totalFamilies; i++) {
873  if (shapeFamilies[i].distributionType == 4) { // Constant
874  std::cout << shapeType(shapeFamilies[i]) << " Family "
875  << getFamilyNumber(i, shapeFamilies[i].shapeFamily) << "\n"
876  << "Using constant size\n\n";
877 
878  file << shapeType(shapeFamilies[i]) << " Family "
879  << getFamilyNumber(i, shapeFamilies[i].shapeFamily) << "\n"
880  << "Using constant size\n\n";
881 
882  }
883  else {
884  std::cout << shapeType(shapeFamilies[i]) << " Family "
885  << getFamilyNumber(i, shapeFamilies[i].shapeFamily) << "\n"
886  << "Estimated: " << pstats.expectedFromFam[i] << "\n";
887  std::cout << "Actual: " << pstats.acceptedFromFam[i] + pstats.rejectedFromFam[i] << "\n\n";
888 
889  file << shapeType(shapeFamilies[i]) << " Family "
890  << getFamilyNumber(i, shapeFamilies[i].shapeFamily)
891  << "Estimated: " << pstats.expectedFromFam[i] << "\n";
892  file << "Actual: " << pstats.acceptedFromFam[i] + pstats.rejectedFromFam[i] << "\n\n";
893  }
894 
895  }
896  std::cout << "\n________________________________________________________\n\n";
897  file << "\n________________________________________________________\n\n";
898  }
899 
900 
901  std::cout << "Seed: " << seed << "\n";
902  file << "Seed: " << seed << "\n";
903 
904  // Write all output files
905  writeOutput(argv[2], acceptedPoly, intPts, triplePoints, pstats, finalFractures, shapeFamilies);
906 
907  // Duplicate node counters are set in writeOutput(). Write output must happen before
908  // duplicate node prints
909  // Print number of duplicate nodes (pstats.intersectionsNodeCount is set in writeOutpu() )
910  std::cout << "\nLagrit Should Remove "
911  << pstats.intersectionNodeCount/2 - pstats.tripleNodeCount
912  << " Nodes (" << pstats.intersectionNodeCount << "/2 - "
913  << pstats.tripleNodeCount << ")\n";
914 
915  file << "\nLagrit Should Remove "
916  << pstats.intersectionNodeCount/2 - pstats.tripleNodeCount
917  << " Nodes (" << pstats.intersectionNodeCount << "/2 - "
918  << pstats.tripleNodeCount << ")\n";
919 
920  file.close();
921  return 0;
922 }
923 
924 /******************************** END MAIN ***********************************/
925 /*****************************************************************************/
926 
927 
void reset_terminal_mode()
Definition: hotkey.cpp:12
void adjustCDF_and_famProb(float *&CDF, float *&famProbability, int &cdfSize, int idx2Remove)
void dryRun(std::vector< Shape > &shapeFamilies, float *shapeProb, std::mt19937_64 &generator, Distributions &distributions)
bool p32Complete(int size)
void insertUserRectsByCoord(std::vector< Poly > &acceptedPoly, std::vector< IntPoints > &intpts, struct Stats &pstats, std::vector< Point > &triplePoints)
bool truncated
Definition: structures.h:95
unsigned long long int shortIntersection
Definition: structures.h:252
double areaAfterRemoval
Definition: structures.h:324
unsigned long long int closeToNode
Definition: structures.h:255
unsigned long long int closeToEdge
Definition: structures.h:258
unsigned long long int triple
Definition: structures.h:264
void set_conio_terminal_mode()
Definition: hotkey.cpp:23
unsigned int intersectionsShortened
Definition: structures.h:344
unsigned int nPoly
Definition: readInput.cpp:15
double originalLength
Definition: structures.h:347
double eps
Definition: DFNmain.cpp:39
unsigned long long int interCloseToInter
Definition: structures.h:267
bool userRecByCoord
Definition: readInput.cpp:340
std::string shapeType(struct Shape &shapeFam)
void getInput(char *input, std::vector< Shape > &shapeFamily)
Definition: readInput.cpp:485
bool userRectanglesOnOff
Definition: readInput.cpp:336
bool outputAllRadii
Definition: readInput.cpp:357
double getArea(struct Poly &poly)
unsigned int truncated
Definition: structures.h:311
float * createCDF(float *famProb, int size)
unsigned int seed
Definition: readInput.cpp:105
struct RejectionReasons rejectionReasons
Definition: structures.h:339
float * layers
Definition: readInput.cpp:443
int getch()
Definition: hotkey.cpp:57
bool userEllipsesOnOff
Definition: readInput.cpp:306
unsigned long long int closePointToEdge
Definition: structures.h:260
unsigned int intersectionNodeCount
Definition: structures.h:358
int * expectedFromFam
Definition: structures.h:296
bool insertUserRectanglesFirst
Definition: readInput.cpp:96
double discardedLength
Definition: structures.h:352
void insertUserEllByCoord(std::vector< Poly > &acceptedPoly, std::vector< IntPoints > &intpts, struct Stats &pstats, std::vector< Point > &triplePoints)
int rejectsPerFracture
Definition: readInput.cpp:439
unsigned long long int outside
Definition: structures.h:262
float radiiListIncrease
Definition: readInput.cpp:26
std::vector< unsigned int > getCluster(Stats &pstats)
double areaBeforeRemoval
Definition: structures.h:320
int getFamilyNumber(int familyIndex, int familyShape)
std::vector< unsigned int > rejectsPerAttempt
Definition: structures.h:371
void addRadiiToLists(float percent, std::vector< Shape > &shapeFamilies, std::mt19937_64 &generator, Distributions &distributions)
void insertUserRects(std::vector< Poly > &acceptedPoly, std::vector< IntPoints > &intpts, struct Stats &pstats, std::vector< Point > &triplePoints)
void writeOutput(char *outputFolder, std::vector< Poly > &acceptedPoly, std::vector< IntPoints > &intPts, std::vector< Point > &triplePoints, struct Stats &pstats, std::vector< unsigned int > &finalFractures, std::vector< Shape > &shapeFamilies)
Definition: output.cpp:31
void assignAperture(struct Poly &newPoly, std::mt19937_64 &generator)
int main(int argc, char **argv)
Definition: DFNmain.cpp:42
double volBeforeRemoval
Definition: structures.h:328
double * vertices
Definition: structures.h:70
int * acceptedFromFam
Definition: structures.h:283
void assignPermeability(struct Poly &newPoly)
double volAfterRemoval
Definition: structures.h:332
void insertUserEll(std::vector< Poly > &acceptedPoly, std::vector< IntPoints > &intpts, struct Stats &pstats, std::vector< Point > &triplePoints)
void printPolyData(struct Poly &poly)
double yradius
Definition: structures.h:46
struct termios orig_termios
Definition: DFNmain.cpp:36
void createBoundingBox(struct Poly &newPoly)
unsigned int retranslatedPolyCount
Definition: structures.h:308
void generateRadiiLists_nPolyOption(std::vector< Shape > &shapeFamilies, float *famProb, std::mt19937_64 &generator, Distributions &distributions)
int nFamEll
Definition: readInput.cpp:120
int kbhit()
Definition: hotkey.cpp:44
float * famProb
Definition: readInput.cpp:133
unsigned int tripleNodeCount
Definition: structures.h:364
bool domainTruncation(Poly &newPoly, double *domainSize)
Definition: domain.cpp:19
double xradius
Definition: structures.h:40
int indexFromProb(float *CDF, double roll, int size)
void reTranslatePoly(struct Poly &newPoly, struct Shape &shapeFam, std::mt19937_64 &generator)
int nFamRect
Definition: readInput.cpp:116
struct Poly generatePoly(struct Shape &shapeFam, std::mt19937_64 &generator, Distributions &distributions, int familyIndex, bool useList)
Definition: insertShape.cpp:26
bool printRejectReasons
Definition: readInput.cpp:67
int * rejectedFromFam
Definition: structures.h:289
bool * p32Status
Definition: readInput.cpp:468
void removeFractures(double minSize, std::vector< Poly > &acceptedPolys, std::vector< IntPoints > &intPts, std::vector< Point > triplePoints, Stats &pstats)
bool userEllByCoord
Definition: readInput.cpp:344
bool ignoreBoundaryFaces
Definition: readInput.cpp:473
float area
Definition: structures.h:33
int intersectionChecking(struct Poly &newPoly, std::vector< Poly > &acceptedPoly, std::vector< IntPoints > &intPtsList, struct Stats &pstats, std::vector< Point > &triplePoints)
void printRejectReason(int rejectCode, struct Poly newPoly)
float removeFracturesLessThan
Definition: readInput.cpp:260
double domainSize[3]
Definition: readInput.cpp:18
void printShapeFams(std::vector< Shape > &shapeFamilies)
int familyNum
Definition: structures.h:22
int indexFromProb_and_P32Status(float *CDF, double roll, int famSize, int cdfSize, int &cdfIdx)
double h
Definition: readInput.cpp:21
bool disableFram
Definition: readInput.cpp:30
void sortRadii(std::vector< Shape > &shapeFam)
unsigned int getTimeBasedSeed()
unsigned int acceptedPolyCount
Definition: structures.h:300
float * layerVol
Definition: readInput.cpp:447
short stopCondition
Definition: readInput.cpp:12
unsigned long long int rejectedPolyCount
Definition: structures.h:304