ODT
Loading...
Searching...
No Matches
meshManager.cc
Go to the documentation of this file.
1
6#include "meshManager.h"
7#include "domain.h"
8#include "param.h"
9#include <cmath>
10#include <cstdlib>
11#include <algorithm>
12#include <iostream>
13#include <numeric> //accumulate
14
15using namespace std;
16
18
24void meshManager::init(domain *p_domn, const vector<dv*> p_phi) {
25
26 domn = p_domn;
27 phi = p_phi;
28
29 lastDA = vector<double>(domn->pram->sLastDA, 0.0);
30
31}
32
34
40void meshManager::adaptGrid(int iLowerDummy, int iUpperDummy) {
41
42 for(int i=0; i<phi.size(); i++)
43 phi.at(i)->setVar();
44
45 for (int i=0; i < domn->ngrd; i++) {
46 if(domn->posf->d.at(i) > domn->posf->d.at(i+1)){
47 *domn->io->ostrm << endl << "ERROR: Non-increasing domain!" << endl;
48 //domn->io->outputProperties("ERROR_domain.dat");
49 exit(0);
50 }
51 }
52
53 if(!domn->pram->LmultiPhase){
54 // case is for a single phase
55 if(iLowerDummy == iUpperDummy)
56 return;
57
58 if(iLowerDummy < iUpperDummy) {
59 adaptGrid_details(iLowerDummy, iUpperDummy);
60 }
61
62 //---------- for periodic where adaption region wraps, adapt twice: once on each section
63
64 else {
65
66 posUpper = domn->posf->d.at(iUpperDummy+1);
67
68 adaptGrid_details(iLowerDummy, domn->ngrd-1);
69
70 iUpperDummy = domn->domainPositionToIndex(posUpper, false, 12);
71
72 adaptGrid_details(0, iUpperDummy);
73 }
74 }
75 else {
76 // case is for multiple immiscable phases
77 if(iLowerDummy == iUpperDummy)
78 return;
79 if(iLowerDummy < iUpperDummy){
80
81 double posUpperDummy = domn->posf->d.at(iUpperDummy+1);
82 double posMiddDummy;
83 double phase = domn->phase->d.at(iLowerDummy);
84
85 for (int iDummy = iLowerDummy+1; iDummy <= iUpperDummy; iDummy++){
86 if (phase != domn->phase->d.at(iDummy)){
87
88 // change to new Phase
89 phase = domn->phase->d.at(iDummy);
90
91 // save position of phase change
92 posMiddDummy = domn->posf->d.at(iDummy);
93
94 // adapt grid within the old phase
95 adaptGrid_details(iLowerDummy, iDummy-1);
96
97 // recover indexes
98 iUpperDummy = domn->domainPositionToIndex(posUpperDummy, false, 13);
99 iLowerDummy = domn->domainPositionToIndex(posMiddDummy, true, 14);
100 iDummy = iLowerDummy;
101 }
102 }
103
104 // adaption of the last phase
105 adaptGrid_details(iLowerDummy, iUpperDummy);
106 }
107
108 //---------- for periodic where adaption region wraps, adapt twice: once on each section
109 else{
110 posUpper = domn->posf->d.at(iUpperDummy+1);
111
112 // call adaptGrid twice, once for the lower part and once for the
113 // upper part. adaptGrid is needet to take different phases into
114 // account.
115 adaptGrid(iLowerDummy, domn->ngrd-1);
116
117 iUpperDummy = domn->domainPositionToIndex(posUpper, false, 15);
118
119 adaptGrid(0, iUpperDummy);
120 }
121 }
122
123// if(domn->pram->cCoord != 1) removeFaceNearZero();
124// if(domn->pram->cCoord != 1) makeCellWithZeroSymmetric();
125// if(domn->pram->cCoord != 1) splitCellWithZero();
126
127}
128
129
131
138void meshManager::adaptGrid_details(int iLowerDummy, int iUpperDummy) {
139
140 // set xf and yf in the region to adapt
141
142 iLower = iLowerDummy;
143 iUpper = iUpperDummy;
144 posLower = domn->posf->d.at(iLower);
145 posUpper = domn->posf->d.at(iUpper+1);
146
147
148 xf = vector<double>(domn->posf->d.begin()+iLower, // face positions
149 domn->posf->d.begin()+iUpper+2);
150
151 yf = vector<vector<double> >(phi.size(), vector<double>(xf.size(), 0.0));
152
153 for(int iProf = 0; iProf<(int)phi.size(); iProf++) {
154
155 if(iLower==0)
156 yf.at(iProf).at(0) = phi.at(iProf)->d.at(0);
157 else
158 yf.at(iProf).at(0) = phi.at(iProf)->d.at(iLower-1) + (domn->posf->d.at(iLower)-domn->pos->d.at(iLower-1))/
159 (domn->pos->d.at(iLower)-domn->pos->d.at(iLower-1))*
160 (phi.at(iProf)->d.at(iLower)-phi.at(iProf)->d.at(iLower-1));
161 if(iUpper==domn->ngrd-1)
162 yf.at(iProf).at(xf.size()-1) = phi.at(iProf)->d.at(iUpper);
163 else
164 yf.at(iProf).at(xf.size()-1) = phi.at(iProf)->d.at(iUpper) + (domn->posf->d.at(iUpper+1)-domn->pos->d.at(iUpper))/
165 (domn->pos->d.at(iUpper+1)-domn->pos->d.at(iUpper))*
166 (phi.at(iProf)->d.at(iUpper+1)-phi.at(iProf)->d.at(iUpper));
167 for(int i=1,j=iLower+i; i<(int)xf.size()-1; i++, j++) {
168 yf.at(iProf).at(i) = phi.at(iProf)->d.at(j-1) + (domn->posf->d.at(j)-domn->pos->d.at(j-1))/
169 (domn->pos->d.at(j)-domn->pos->d.at(j-1))*
170 (phi.at(iProf)->d.at(j)-phi.at(iProf)->d.at(j-1));
171 }
172 }
173 //---------- Scale xf and yf
174
175 //double xfMax = *max_element(xf.begin(), xf.end());
176 //double xfMin = *min_element(xf.begin(), xf.end());
177 double xfMax = *max_element(domn->posf->d.begin(), domn->posf->d.end());
178 double xfMin = *min_element(domn->posf->d.begin(), domn->posf->d.end());
179 for(int i=0; i<(int)xf.size(); i++)
180 xf.at(i) = (xf.at(i)-xfMin)/(xfMax-xfMin);
181
182 for(int iProf = 0; iProf<(int)phi.size(); iProf++) {
183 //double yfMax = *max_element(yf.at(iProf).begin(), yf.at(iProf).end());
184 //double yfMin = *min_element(yf.at(iProf).begin(), yf.at(iProf).end());
185 double yfMax = *max_element(phi.at(iProf)->d.begin(), phi.at(iProf)->d.end());
186 double yfMin = *min_element(phi.at(iProf)->d.begin(), phi.at(iProf)->d.end());
187 for(int i=0; i<(int)xf.size(); i++)
188 yf.at(iProf).at(i) = (yf.at(iProf).at(i)-yfMin)/(yfMax-yfMin);
189 }
190
191 //---------- Compute the new grid distance function
192
193 vector<double> s_dist(xf.size(),0.0); // distance function for x,y
194 vector<double> sn_dist; // new distance function for new grid X,Y
195
196 double s_distCum = calcDistance(xf, yf, s_dist);
197
198 int nNewGrd = domn->pram->gDens*s_distCum+1;
199
200 sn_dist.resize(nNewGrd+1, 0.0);
201 xnf.resize(nNewGrd+1, 0.0);
202
203 double dS = s_distCum / nNewGrd;
204 sn_dist.at(0) = 0.0;
205 for(int i=1, im=0; i<nNewGrd+1; i++, im++)
206 sn_dist.at(i) = sn_dist.at(im) + dS;
207
208 //---------- Get the new grid using the old grid, old dist func, new dist func
209
210 interpVec(s_dist, xf, sn_dist, xnf); // interp from xf --> xnf
211
212 for(int i=0; i<(int)xnf.size(); i++) // Unscale xnf
213 xnf.at(i) = xfMin + xnf.at(i)*(xfMax-xfMin);
214
215 xnf.at(0) = posLower;
216 xnf.at(xnf.size()-1) = posUpper;
217 for(int i=0; i<(int)xnf.size(); i++) // doldb ?
218 if(xnf.at(i) < posLower || xnf.at(i) > posUpper) {
219 *domn->io->ostrm << endl << "Error in mesher: X is out of bounds, i= " << i << endl;
220 *domn->io->ostrm << " posLower, posUpper, xnf.at(i) ,xnf.at(0), xnf.at(end) = " <<
221 posLower << ", " << posUpper << ", " << xnf.at(i)<< ", " << xnf.at(0)<< ", " << xnf.at(xnf.size()-1) << endl;
222 exit(0);
223 }
224
225 for(int i=1; i<(int)xnf.size(); i++) // doldb ?
226 if(xnf.at(i) <= xnf.at(i-1)) {
227 //domn->io->outputProperties("domain_before_error.dat");
228 *domn->io->ostrm << endl << endl;
229 *domn->io->ostrm << "i = " << i << " xnf.size = " << xnf.size() << " xnf = "
230 << xnf.at(i-1) <<" "<< xnf.at(i) << endl;
231 *domn->io->ostrm << endl << "Error in mesher: xnf is nonincreasing " << endl;
232 exit(0);
233 }
234
235 //--------- Add in the rest of the old grid so that we can adapt desired region of WHOLE domain
236
237 if(iLower > 0)
238 xnf.insert(xnf.begin(), domn->posf->d.begin(), domn->posf->d.begin()+iLower);
239 if(iUpper < domn->ngrd-1)
240 xnf.insert(xnf.end(), domn->posf->d.begin()+iUpper+2, domn->posf->d.end());
241
243
244 //---------- Adapt the new grid
245
246 ngrdf = xnf.size();
247 ngrd = ngrdf-1;
248 setDxArray();
250
251 //----------- split large cells
252
253 for (int i=0; i<ngrd; i++) {
254 if (dx.at(i) > domn->pram->dxmax){
255 dx.at(i) *= 0.5;
256 dx.insert(dx.begin()+i,dx.at(i));
257 ngrd++;
258 ngrdf++;
259 i--;
260 }
261 }
262 xnf.resize(ngrdf);
263 xnf.at(0) = domn->posf->d.at(0); // recover the grid
264 for(int i=1; i<ngrdf; i++)
265 xnf.at(i) = xnf.at(i-1)+dx.at(i-1);
266
267 //----------- Small Cells
268
269 if(domn->pram->LmultiPhase)
270 mergeSmallCellsMP(); // Function does the same as the old one, but has a phase check
271 else
272 mergeSmallCells(); // Function does the same as the old one, but has a phase check
273
274 xnf.resize(ngrdf);
275 xnf.at(0) = domn->posf->d.at(0); // recover the grid
276 for(int i=1; i<ngrdf; i++)
277 xnf.at(i) = xnf.at(i-1)+dx.at(i-1);
278
279 set_iLower_iUpper(); // recover the bounds
280
281 //----------- 2.5 rule
282
283 impose2point5rule(); // modifies dx, ngrd, ngrdf (but xnf is now inconsisten)
284
285 xnf.resize(ngrdf);
286 xnf.at(0) = domn->posf->d.at(0); // recover the grid
287 for(int i=1; i<ngrdf; i++)
288 xnf.at(i) = xnf.at(i-1)+dx.at(i-1);
289
290 //---------- Apply new grid to odt domain:
291
292 //---------- split domn where new grid has faces that don't match domn.
293 // domn | | | | | |
294 // xnf | :: | | : : : |
295 // domn new | || | | | | | | | |
296
297 vector<double> whereSplit;
298 int iCell;
299
300 double rtol = 1.0E-10*domn->pram->domainLength/domn->ngrd;
301
302 for(int j=1; j<(int)xnf.size()-1; j++) { // loop over new grid cell faces
303
304 iCell = domn->domainPositionToIndex(xnf.at(j), true, 16);
305
306 if(abs(domn->posf->d.at(iCell) - xnf.at(j)) > rtol) {
307 if(abs(domn->posf->d.at(iCell+1) - xnf.at(j)) > rtol) { // far away from next face
308 // this second if is needed due to the fact that somtimes there is
309 // a face in xnf that's exact equal to one face in domn->posf. In
310 // this case a cell with dx=0 is generated which may cause trouble.
311 whereSplit.clear();
312 whereSplit.push_back( xnf.at(j) );
313 j++;
314 for( ; j<(int)xnf.size()-1; j++) {
315
316 if( (abs(domn->posf->d.at(iCell+1) - xnf.at(j)) > rtol)
317 && (domn->posf->d.at(iCell+1) > xnf.at(j)) ) {
318
319 whereSplit.push_back( xnf.at(j) );
320 }
321 else{
322 j--;
323 break;
324 }
325 }
326 // Append the cell left face and right face to whereSplit
327 // We won't split there, but it aids the splitCell functions
328 whereSplit.insert(whereSplit.begin(), domn->posf->d.at(iCell));
329 whereSplit.push_back(domn->posf->d.at(iCell+1));
330 splitCell(iCell, whereSplit.size()-2, whereSplit);
331 }
332 }
333 }
334
335 //---------- merge domn where faces present that are not in new grid
336 // domn new | || | | | | : : | |
337 // xnf | || | | | | | |
338 // domn new | || | | | | | |
339 // now domn matches xnf
340
341 //---------- note, merging cells may change the cell size for conservation, hence all faces move
342 // so mark all, then merge
343
344 mark.clear();
345
346 for(int i=1, j=1; i<domn->ngrdf-1; i++) { // loop over interior faces of domn
347 if( abs(domn->posf->d.at(i)-xnf.at(j)) > rtol)
348 mark.push_back(i-1);
349 else
350 j++;
351 }
352
353 for(int i=mark.size()-1; i>=0; i--) // go backwards so we don't have to update indices in mark
354 merge2cells(mark.at(i), false); // as we merge cells
355 // NOTE: flag true here will result in nonconservative mass/mass
356 // flow in merging, but elininates cell volumes changing accross
357 // the whole domain due to mixing. The meshing should keep the
358 // profiles the same and just change grid points, especially
359 // if it means the grid moves in unphysical ways (well, its not
360 // unphysical since its rigorous mixing when false).
361 // We are really trading one numerical error for another:
362 // shifting versus mass conservation.
363 // Try testing the temporal jet with diffusion bypassed
364 // (return at the top of advanceODT).
365
367}
368
369
371
375
376 iLower = 0;
377 iUpper = ngrd-1;
378
379 if(posLower==xnf.at(ngrd) || posUpper==xnf.at(0)) {
380 *domn->io->ostrm << posLower << " " << posUpper << " " << xnf.at(0) << " " << xnf.at(ngrd) << endl;
381 *domn->io->ostrm << endl << "ERROR in adapMesh posLower/Upper on wrong boundary" << endl;
382 exit(0);
383 }
384 for(int i=0; i<ngrd; i++) {
385 if(posLower < xnf.at(i+1)) {
386 iLower = i;
387 break;
388 }
389 }
390 for(int i=ngrd-1; i>=0; i--) {
391 if(posUpper > xnf.at(i)) {
392 iUpper = i;
393 break;
394 }
395 }
396
397}
398
400
419
420 int i, j;
421
422 //---------- mark the small cells
423
424 mark.clear();
425 for(i=0; i<=ngrd-1; i++)
426 if(dx.at(i) < domn->pram->dxmin)
427 mark.push_back(i);
428
429 //---------- sort the small cells to remove any directional bias
430
431 vector<int> ind(mark.size()); // index map for the sort
432 for(i=0; i<(int)ind.size(); i++) // sort "ind" using dx as sort condition
433 ind.at(i)=i;
434 sort(ind.begin(), ind.end(), *this); // *this invokes the functor "operator()"
435 vector<int> scMark(mark.size()); // reorder the mark array
436 for(i=0; i<(int)ind.size(); i++) // could just use mark.at(ind.at(i)),
437 scMark.at(i) = mark.at(ind.at(i)); // but reorder for simplicity
438
439
440 //---------- merge small cells
441
442 int isc; // small cell index
443 int iSmallerNB; // smaller of 2 neighbors
444 int iend = scMark.size(); // may change as merge cells
445 bool LcellDone; // flag to repeat small cells till big
446
447 //---------------------------------
448
449 for(i=0; i<iend; i++) { // loop over small cells
450
451 isc = scMark.at(i);
452 isc = scMark.at(i);
453 LcellDone = false;
454
455 //---------------------------------
456
457 while(!LcellDone) { // keep going till small cell is done
458
459 if(isc == 0)
460 iSmallerNB = 1;
461 else if(isc == ngrd-1)
462 iSmallerNB = ngrd-2;
463 else
464 iSmallerNB = (dx.at(isc-1) <= dx.at(isc+1)) ? isc-1 : isc+1;
465
466 if(dx.at(iSmallerNB) + dx.at(isc) >= domn->pram->dxmin)
467 LcellDone = true; // if new cell big enough then done
468
469 //---------------------------------
470
471 if(iSmallerNB > isc) {
472
473 // merge cells
474
475 ngrdf--;
476 ngrd--;
477 dx.at(isc) = dx.at(isc) + dx.at(isc+1);
478 dx.erase( dx.begin() + isc+1 );
479
480 // delete cell iSmallerNB from scMark array (if present)
481 // and decrement all cells > isc in scMark
482
483 for(j=i+1; j<iend; j++)
484 if(scMark.at(j) > isc)
485 scMark.at(j)--;
486 for(j=i+1; j<iend; j++)
487 if(scMark.at(j)==isc){
488 scMark.erase(scMark.begin()+j);
489 iend--;
490 break;
491 }
492
493 } // if(iSmallerNB > isc)
494
495 //---------------------------------
496
497 else {
498
499 // merge cells
500
501 ngrdf--;
502 ngrd--;
503 dx.at(isc-1) = dx.at(isc-1) + dx.at(isc);
504 dx.erase( dx.begin() + isc );
505
506 // decrement isc and scMark.at(i) which is isc
507 // delete cell isc-1 in scMark if present
508 // and decrement
509
510 scMark.at(i)--;
511 isc--;
512
513 for(j=i+1; j<iend; j++)
514 if(scMark.at(j) > isc)
515 scMark.at(j)--;
516 for(j=i+1; j<iend; j++)
517 if(scMark.at(j)==isc){
518 scMark.erase(scMark.begin()+j);
519 iend--;
520 break;
521 }
522
523 } // else (i.e., iSmallerNB < isc)
524 //---------------------------------
525 } // end while
526 //---------------------------------
527 } // end loop over small cells
528
529 //---------- update the eddy regions
530
531} // end function
532
533
535
544
545 double x = domn->posf->d.at(0);
546 double xp = 0; // midd point of previous cell
547 double xc = 0; // midd point of current cell
548 double xn = 0; // midd point of next cell
549 double phase_p = 0;
550 double phase_c = 0;
551 double phase_n = 0;
552
553
554 for (int i=0; i<ngrd; i++){
555 if (dx.at(i) >= domn->pram->dxmin)
556 x += dx.at(i);
557 else{
558 // the current cell is too small
559
560 // if it is the first cell
561 if (i == 0){
562 xc = x + dx.at(i)/2;
563 xn = x + dx.at(i)+dx.at(i+1)/2;
564 phase_c = domn->phase->d.at( domn->domainPositionToIndex( xc, true, 17 ) );
565 phase_n = domn->phase->d.at( domn->domainPositionToIndex( xn, true, 18 ) );
566
567 if (phase_c == phase_n){
568 ngrdf--;
569 ngrd--;
570 dx.at(i) = dx.at(i) + dx.at(i+1);
571 dx.erase( dx.begin() + i+1 );
572 i--;
573 } else{
574 x += dx.at(i);
575 }
576 continue;
577 }
578
579 // if it is the last cell
580 if (i == ngrd-1){
581 xp = x - dx.at(i-1)/2;
582 xc = x + dx.at(i)/2;
583 phase_p = domn->phase->d.at( domn->domainPositionToIndex( xp, true, 19 ) );
584 phase_c = domn->phase->d.at( domn->domainPositionToIndex( xc, true, 20 ) );
585
586 if (phase_p == phase_c){
587 ngrdf--;
588 ngrd--;
589 x -= dx.at(i-1); // subtracting the dx of the previous cell, added in the last loop step
590 dx.at(i-1) = dx.at(i-1) + dx.at(i);
591 dx.erase( dx.begin() + i );
592 i--; i--;
593 } else{
594 x += dx.at(i);
595 }
596 continue;
597 }
598
599 // it is a cell in the midd of the domain
600 xp = x - dx.at(i-1)/2; // cell center of previous cell
601 xc = x + dx.at(i)/2; // cell center of current cell
602 xn = x + dx.at(i) + dx.at(i+1)/2; // cell center of next cell
603 phase_p = domn->phase->d.at( domn->domainPositionToIndex( xp, true, 21 ) );
604 phase_c = domn->phase->d.at( domn->domainPositionToIndex( xc, true, 22 ) );
605 phase_n = domn->phase->d.at( domn->domainPositionToIndex( xn, true, 23 ) );
606
607 // the case, that the previous cell has another phase
608 if (phase_p != phase_c && phase_c == phase_n){
609 // the next cell has to be taken for merging cells
610 ngrdf--;
611 ngrd--;
612 dx.at(i) = dx.at(i) + dx.at(i+1);
613 dx.erase( dx.begin() + i+1 );
614 i--;
615 continue;
616 }
617
618 // the case, that the next cell has another phase
619 if (phase_p == phase_c && phase_c != phase_n){
620 // the previous cell has to be taken for merging cells
621 ngrdf--;
622 ngrd--;
623 x -= dx.at(i-1); // subtracting the dx of the previous cell, added in the last loop step
624 dx.at(i-1) = dx.at(i-1) + dx.at(i);
625 dx.erase( dx.begin() + i );
626 i--; i--;
627 continue;
628 }
629
630 // the case, that both neighbor cells have different phases
631 if (phase_p != phase_c && phase_c != phase_n){
632 x += dx.at(i);
633 continue;
634 }
635
636 // the last case, that all three cells have the same phase
637 if (phase_p == phase_c && phase_c == phase_n){
638 // the smaller one of both neighbor cells has to be taken
639 if (dx.at(i-1) < dx.at(i+1)){
640 // the previous neigbor has to be taken
641 ngrdf--;
642 ngrd--;
643 x -= dx.at(i-1); // subtracting the dx of the previous cell, added in the last loop step
644 dx.at(i-1) = dx.at(i-1) + dx.at(i);
645 dx.erase( dx.begin() + i );
646 i--; i--;
647 } else{
648 // the next neigbor has to be taken
649 ngrdf--;
650 ngrd--;
651 dx.at(i) = dx.at(i) + dx.at(i+1);
652 dx.erase( dx.begin() + i+1 );
653 i--;
654 }
655 continue;
656 } else{
657 *domn->io->ostrm << "\n\ni = " << i;
658 *domn->io->ostrm << "\nphase_p = " << phase_p;
659 *domn->io->ostrm << "\nphase_c = " << phase_c;
660 *domn->io->ostrm << "\nphase_n = " << phase_n;
661 *domn->io->ostrm << "\n(phase_p != phase_c && phase_c == phase_n) = " << (phase_p != phase_c && phase_c == phase_n);
662 *domn->io->ostrm << "\n(phase_p != phase_c && phase_c == phase_n) = " << (phase_p == phase_c && phase_c != phase_n);
663 *domn->io->ostrm << "\n(phase_p != phase_c && phase_c == phase_n) = " << (phase_p != phase_c && phase_c != phase_n);
664 *domn->io->ostrm << "\n(phase_p != phase_c && phase_c == phase_n) = " << (phase_p == phase_c && phase_c == phase_n);
665 *domn->io->ostrm << "\nERROR: In the function meshManager::mergeSmallCells_MP()"
666 << endl << "This error might not be there caused by logic one of the"
667 << endl << "previous cases have to occur."
668 << endl << "There must be a NaN problem.";
669 exit(0);
670 }
671 }
672 }
673}
674
675
677
682
683 int i;
684 double d1;
685
686 //---------- set the mark array with offending cells
687
688 mark.clear();
689 int iHi = (iUpper < ngrd-1) ? iUpper : iUpper-1;
690 int iLo = (iLower > 0) ? iLower-1 : iLower;
691 //int iHi = ngrd-2;
692 //int iLo = 0;
693 for(i=iLo; i<=iHi; i++) {
694 d1 = dx.at(i)/dx.at(i+1);
695 if(d1 > 2.5 || d1 < 0.4)
696 mark.push_back(i);
697 }
698 i = ngrd-1;
699 if(domn->pram->Lperiodic && iUpper==i) {
700 d1 = dx.at(i)/dx.at(0);
701 if(d1 > 2.5 || d1 < 0.4)
702 mark.push_back(i);
703 }
704
705 //-------- loop over each marked cell and fix the 2.5 offenders
706
707 for(i=0; i<(int)mark.size(); i++)
708 fix2point5offender(mark.at(i), i);
709
710}
711
713
770void meshManager::fix2point5offender(const int mPos, const int &iglobal) {
771
772
773 //--------- Simply return if you pass the test
774
775 int ip = (mPos == ngrd-1) ? 0 : mPos+1;
776 double ratio = (dx.at(mPos) < dx.at(ip)) ? dx.at(ip)/dx.at(mPos) : dx.at(mPos)/dx.at(ip);
777 if(ratio < 2.5)
778 return;
779
780 //--------- Split the larger of the two cells
781
782 int i;
783 int isplt = (dx.at(mPos) < dx.at(ip)) ? ip : mPos; // split larger of 2 cells
784 int nsplt = static_cast<int>(log2(ratio / 2.5)) + 1 ; // how many splits to do
785
786 vector<double> icp(nsplt); // pos of new intrnl cell fcs (rel to lft edge)
787
788 bool splitCellOnRight = (isplt > mPos);
789 if(mPos == ngrd-1 && isplt == 0) // for periodic
790 splitCellOnRight = true;
791
792 if(splitCellOnRight) { // | | : : : | --> nsplt=3
793 icp.at(nsplt-1) = dx.at(isplt)*0.5;
794 for(i=nsplt-2; i>=0; i--)
795 icp.at(i) = icp.at(i+1)*0.5;
796
797 for(i=nsplt-1; i>=1; i--) // update dx arr, reuse icp arr
798 icp.at(i) -= icp.at(i-1); // i.e. we inserted cells, so insert dx
799 dx.at(isplt) *= 0.5; // icp was positions, now are dx's
800 dx.insert(dx.begin()+isplt, icp.begin(), icp.end());
801 }
802 else { // | : : : | | --> nsplt=3
803 icp.at(0) = dx.at(isplt)*0.5;
804 for(i=1; i<nsplt; i++) // set icp as dx's : 1/2, 1/4, 1/8 ...
805 icp.at(i) = icp.at(i-1)*0.5;
806 for(i=1; i<nsplt; i++) // now offset to 0.5, 0.75, 0.876 ...
807 icp.at(i) += icp.at(i-1);
808
809 for(i=0; i<nsplt-1; i++) // update dx arr, reuse icp arr
810 icp.at(i) = icp.at(i+1) - icp.at(i);
811 if(nsplt >=2)
812 icp.at(nsplt-1) = icp.at(nsplt-2);
813 dx.at(isplt) *= 0.5;
814 dx.insert(dx.begin()+isplt+1, icp.begin(), icp.end());
815 }
816
817 ngrd += nsplt; // update meshManager's ngrd, ngrdf (domn's are done)
818 ngrdf += nsplt;
819
820 //--------- Update the mark array
821
822 for(i=iglobal+1; i<(int)mark.size(); i++)
823 if(mark.at(i) > isplt)
824 mark.at(i) += nsplt;
825
826 //--------- Now compare the other half of the split cell with neighbor
827
828 int inext;
829 if(splitCellOnRight) {
830 inext = isplt + nsplt;
831 if(inext == ngrd-1 && !domn->pram->Lperiodic)
832 return;
833 }
834 else {
835 inext = mPos-1;
836 if(inext == -1) {
837 if(!domn->pram->Lperiodic)
838 return;
839 else
840 inext = ngrd-1;
841 }
842 }
843
844 fix2point5offender(inext, iglobal); // recursive call
845
846}
847
849
853
854 dx.resize(ngrd);
855 for(int i=0, ip=1; i<ngrd; i++, ip++)
856 dx.at(i) = xnf.at(ip) - xnf.at(i);
857
858}
859
860
862
869int meshManager::findPos(const vector<double> &x, const double val, const int &istart) {
870
871 if(val <= x.at(0))
872 return 0;
873 if(val >= x.at(x.size()-1))
874 return x.size()-2;
875 for(int i=istart; i<(int)x.size(); i++)
876 if(x.at(i) >= val) {
877 return i-1;
878 }
879 return 0;
880}
881
882
884
892void meshManager::interp1pt(const vector<double> &x, const vector<double> &y,
893 const double &xval, double &yval, int &istart) {
894
895 int i, ip;
896
897 i = findPos(x, xval, istart);
898 ip = i+1;
899 if(i>0)
900 istart = i-1;
901
902 yval = y.at(i) + (xval-x.at(i))*(y.at(ip)-y.at(i))/(x.at(ip)-x.at(i));
903
904}
905
906
908
915void meshManager::interpVec(const vector<double> &x, const vector<double> &y,
916 const vector<double> &xn, vector<double> &yn) {
917
918 if(x.size() != y.size() || xn.size() != yn.size()) {
919 cerr << "\nERROR IN INTERPVEC" << endl;
920 exit(0);
921 }
922 int istart = 0;
923 for(int i=0; i<(int)xn.size(); i++)
924 interp1pt(x,y,xn.at(i),yn.at(i), istart);
925}
926
927
929
937double meshManager::calcDistance(const vector<double> &x, const vector<vector<double> > &y,
938 vector<double> &sDist) {
939
940 double dx2, dy2; // dx^2 and dy^2
941 double dmb;
942
943 sDist.at(0) = 0.0;
944 for (int i=1; i<(int)x.size(); i++) {
945
946 dx2 = x.at(i)-x.at(i-1);
947 dx2 *= dx2;
948
949 dy2 = 0.0;
950 for(int iProf=0; iProf<(int)y.size(); iProf++) {
951 dmb = y.at(iProf).at(i) - y.at(iProf).at(i-1);
952 dmb *= dmb;
953 if(dmb > dy2) dy2 = dmb;
954 }
955
956 sDist.at(i)= sDist.at(i-1)+sqrt(dx2 +dy2);
957 }
958
959 return sDist.at(sDist.size()-1);
960}
961
962
964
971void meshManager::splitCell(const int isplt, const int nsplt, const vector<double> &cellFaces) {
972
973 for(int i=0; i< domn->v.size(); i++)
974 domn->v.at(i)->splitCell(isplt, nsplt, cellFaces);
975
976 domn->ngrd += nsplt;
977 domn->ngrdf += nsplt;
978
979}
980
982
1078void meshManager::merge2cells(const int imrg, const bool LconstVolume) {
1079
1080 double dxc1, dxc2; // cell volumes (imrg, imrg+1, final merged cell) = delta(x^c)
1081 double pm1; // +1 or -1 to change sign
1082
1083 pm1 = domn->posf->d.at(imrg+1)*domn->posf->d.at(imrg) < 0 ? -1.0 : 1.0; // handles cells that split x=0
1084 dxc1 = abs( pow(abs(domn->posf->d.at(imrg+1)), domn->pram->cCoord) -
1085 pm1*pow(abs(domn->posf->d.at(imrg) ), domn->pram->cCoord) );
1086 pm1 = domn->posf->d.at(imrg+2)*domn->posf->d.at(imrg+1) < 0 ? -1.0 : 1.0;
1087 dxc2 = abs( pow(abs(domn->posf->d.at(imrg+2)), domn->pram->cCoord) -
1088 pm1*pow(abs(domn->posf->d.at(imrg+1) ), domn->pram->cCoord) );
1089
1090 double m1 = dxc1 * domn->rho->d.at(imrg);
1091 double m2 = dxc2 * domn->rho->d.at(imrg+1);
1092
1093 if(domn->pram->Lspatial) {
1094 m1 *= domn->uvel->d.at(imrg); // m is now mdot
1095 m2 *= domn->uvel->d.at(imrg+1);
1096 }
1097
1098 //------- merge all but rho, pos, posf (if spatial and LconstVolume this step is redundant for uvel)
1099
1100 for(int k=0; k<domn->v.size(); k++) {
1101 if(domn->v.at(k)->var_name=="rho" || domn->v.at(k)->var_name=="pos" || domn->v.at(k)->var_name=="posf")
1102 continue;
1103 domn->v.at(k)->merge2cells(imrg, m1, m2, LconstVolume);
1104 }
1105 //------- now finish up
1106
1107 domn->rho->merge2cells( imrg, m1, m2, LconstVolume);
1108 if(domn->pram->Lspatial && LconstVolume) {
1109 domn->uvel->d.at(imrg) = (m1 + m2) / (domn->rho->d.at(imrg) * (dxc1+dxc2));
1110 }
1111 domn->ngrd--;
1112 domn->ngrdf--;
1113 domn->posf->merge2cells(imrg, m1, m2, LconstVolume);
1114 // domn->pos is done in posf on previous domain
1115
1116}
1117
1119
1132 double &tLastDA,
1133 int &cLastDA,
1134 double &dtCUmax) {
1135
1136
1137 if(time - tLastDA < domn->pram->DAtimeFac * dtCUmax)
1138 return;
1139
1140 int iStart, iEnd;
1141
1142 double youngsters = domn->pram->DAtimeFac*dtCUmax;
1143
1144 while(time - tLastDA >= youngsters) {
1145
1146 //---------- initialize searches
1147
1148 int leftSide = cLastDA;
1149 int rightSide = (cLastDA == domn->pram->sLastDA-1) ? cLastDA : cLastDA+1;
1150
1151 //---------- search for leftSide
1152
1153 while(time - lastDA.at(leftSide) >= 0.5 * youngsters){
1154 if(leftSide == 0)
1155 break;
1156 leftSide--;
1157 }
1158
1159 //---------- correct for possible overshoot
1160
1161 if(time - lastDA.at(leftSide) < 0.5 * youngsters)
1162 leftSide++;
1163
1164 //---------- search for rightSide
1165
1166 while(time - lastDA.at(rightSide) >= 0.5 * youngsters){
1167 if(rightSide == domn->pram->sLastDA-1)
1168 break;
1169 rightSide++;
1170 }
1171
1172 //---------- correct for possible overshoot
1173
1174 if(time - lastDA.at(rightSide) < 0.5 * youngsters)
1175 rightSide--;
1176
1177 //---------- find the corresponding range of indices of the posf array
1178
1179 iStart = domn->domainPositionToIndex(domn->posf->d[0]+leftSide *domn->Ldomain()/domn->pram->sLastDA, true, 24);
1180 iEnd = domn->domainPositionToIndex(domn->posf->d[0]+rightSide*domn->Ldomain()/domn->pram->sLastDA, false, 25);
1181
1182 updateDA(time, tLastDA, cLastDA, iStart, iEnd);
1183
1184 //---------- adapt the domain
1185
1186 adaptGrid(iStart, iEnd);
1187 }
1188}
1189
1191
1205void meshManager::updateDA(const double &time, double &tLastDA, int &cLastDA,
1206 int iStart, int iEnd) {
1207
1208 //----------- find the range of affected lastDA cells
1209
1210 int leftCell = static_cast<int>(domn->pram->sLastDA * (domn->posf->d.at(iStart)-domn->posf->d.at(0)) / domn->Ldomain());
1211 if(leftCell==domn->pram->sLastDA) leftCell--;
1212 int rightCell = static_cast<int>(domn->pram->sLastDA * (domn->posf->d.at(iEnd+1)-domn->posf->d.at(0)) / domn->Ldomain());
1213 if(rightCell == domn->pram->sLastDA) rightCell--;
1214
1215 if(leftCell > rightCell && !domn->pram->Lperiodic)
1216 return; // no affected cells of LastDA array
1217
1218 //---------- set the lastDA values in this range equal to the current time
1219
1220 if(leftCell > rightCell) { // region like | * | * | | | * | * |
1221 for(int i=leftCell; i<domn->pram->sLastDA; i++)
1222 lastDA.at(i) = time;
1223 for(int i=0; i<=rightCell; i++)
1224 lastDA.at(i) = time;
1225 if( !(cLastDA >= leftCell) && !(cLastDA <= rightCell) )
1226 return; // oldest cell is unaffected
1227 }
1228 else { // region like | | * | * | * | * | |
1229 for(int i=leftCell; i<=rightCell; i++)
1230 lastDA.at(i)=time;
1231 if(!( (cLastDA >= leftCell) && (cLastDA <= rightCell) ))
1232 return; // oldest cell is unaffected
1233 }
1234
1235 //---------- find oldest cell: cLastDA, and earliest last adapt time
1236
1237 cLastDA = 0; // initialize cLastDA
1238 for(int i=1; i<domn->pram->sLastDA; i++)
1239 if(lastDA.at(i) < lastDA.at(cLastDA))
1240 cLastDA = i; // find oldest cell
1241 tLastDA = lastDA.at(cLastDA); // earliest last-adapt time
1242
1243}
1244
1246
1255void meshManager::adaptEddyRegionOfMesh(const double &time, double &tLastDA, int &cLastDA) {
1256
1257 int iStart = domn->domainPositionToIndex(domn->ed->leftEdge, true, 4);
1258 int iEnd = domn->domainPositionToIndex(domn->ed->rightEdge, false, 5);
1259
1260 if(iStart > 0) iStart--;
1261 if(iEnd < domn->ngrd-1) iEnd++;
1262
1263 updateDA(time, tLastDA, cLastDA, iStart, iEnd);
1264
1265 adaptGrid(iStart, iEnd);
1266
1267}
1268
1270
1279
1280 if( (domn->pram->bcType=="WALL" && (domn->pram->vBClo==0 || domn->pram->vBChi==0)))
1281 return;
1282
1283 double Ld = domn->Ldomain();
1284
1285 //---------------------- OUTFLOW ON BOTH SIDES
1286
1287 if(domn->pram->bcType == "OUTFLOW") {
1288
1289 double delta_hi; // right side: positive if too big --> chop; negative if too small --> expand
1290 double delta_lo; // left side: positive if too big --> chop; negative if too small --> expand
1291
1292 if(domn->pram->cCoord==1 && !domn->pram->LplanarExpCent0) { // planar
1293 delta_hi = 0.5*(Ld - domn->pram->domainLength);
1294 delta_lo = delta_hi;
1295 }
1296 else { // cylindrical or spherical
1297 delta_hi = domn->posf->d.at(domn->ngrd) - 0.5*domn->pram->domainLength;
1298 delta_lo = -domn->posf->d.at(0) - 0.5*domn->pram->domainLength;
1299 }
1300
1301 //----------- Do expansions
1302
1303 if(delta_hi < 0) { // too small --> expand last cell
1304 domn->posf->d.at(domn->ngrd) -= delta_hi;
1305 domn->pos->d.at(domn->ngrd-1) = 0.5*(domn->posf->d.at(domn->ngrd-1) + domn->posf->d.at(domn->ngrd));
1306 }
1307
1308 if(delta_lo < 0) { // too small --> expand first cell
1309 domn->posf->d.at(0) += delta_lo;
1310 domn->pos->d.at(0) = 0.5*(domn->posf->d.at(0) + domn->posf->d.at(1));
1311 }
1312
1313 //----------- Do contractions
1314
1315 vector<double> cellFaces;
1316
1317 if(delta_hi > 0) { // too big --> chop domain on right
1318
1319 //before |----0---|----1---|-----2---------|------3-$----|--4---|---5----|
1320 //after |----0---|----1---|-----2---------|---3----$=4==|==5===|===6====|
1321 // or
1322 //before |----0---|----1---|-----2---------|------3------$--4---|---5----|
1323 //after |----0---|----1---|-----2---------|---3---------$==4===|===5====|
1324 // works if xSplitHi is at the far right face.
1325
1326 double xSplitHi = domn->posf->d.at(domn->ngrd) - delta_hi;
1327 double iSplitHi = domn->domainPositionToIndex(xSplitHi, false, 28);
1328 if(domn->posf->d.at(iSplitHi+1) != xSplitHi) {
1329 cellFaces.push_back(domn->posf->d.at(iSplitHi));
1330 cellFaces.push_back(xSplitHi);
1331 cellFaces.push_back(domn->posf->d.at(iSplitHi+1));
1332 splitCell(iSplitHi, 1, cellFaces);
1333 }
1334 for(int k=0; k<domn->v.size(); k++)
1335 domn->v.at(k)->d.erase(domn->v.at(k)->d.begin()+iSplitHi+1, domn->v.at(k)->d.end());
1336 domn->posf->d.push_back(xSplitHi);
1337 // pos is fine
1338 domn->ngrd -= (domn->ngrd - iSplitHi - 1);
1339 domn->ngrdf = domn->ngrd+1;
1340 }
1341
1342 if(delta_lo > 0) { // too big --> chop domain on left
1343
1344 //before |----0---|----1---|-----$--2------|---3--|---4--|---5--|
1345 //after |====0===|====1===|==2==$----3----|---4--|---5--|---6--|
1346 // or
1347 //before |----0---|----1---$--------2------|---3--|---4--|---5--|
1348 //after |====0===|====1===$--------2------|---3--|---4--|---5--|
1349 // works if xSplitLo is at the far left face.
1350
1351 double xSplitLo = domn->posf->d.at(0) + delta_lo;
1352 double iSplitLo = domn->domainPositionToIndex(xSplitLo, true, 29);
1353 if(domn->posf->d.at(iSplitLo) != xSplitLo) {
1354 cellFaces.resize(0);
1355 cellFaces.push_back(domn->posf->d.at(iSplitLo));
1356 cellFaces.push_back(xSplitLo);
1357 cellFaces.push_back(domn->posf->d.at(iSplitLo+1));
1358 splitCell(iSplitLo, 1, cellFaces);
1359 }
1360 else
1361 iSplitLo--;
1362 for(int k=0; k<domn->v.size(); k++)
1363 domn->v.at(k)->d.erase(domn->v.at(k)->d.begin(), domn->v.at(k)->d.begin()+iSplitLo+1);
1364 // pos and posf are fine
1365 domn->ngrd -= iSplitLo+1;
1366 domn->ngrdf = domn->ngrd+1;
1367 }
1368
1369 //------------- merge first cell and last cell (with neighbors) if small
1370
1371 if(domn->posf->d.at(domn->ngrd) - domn->posf->d.at(domn->ngrd-1) < domn->pram->dxmin)
1372 merge2cells(domn->ngrd-2, false);
1373 if(domn->posf->d.at(1) - domn->posf->d.at(0) < domn->pram->dxmin)
1374 merge2cells(0, false);
1375
1376 } // endif OUTFLOW
1377
1378 //---------------------- Wall on left, outflow on the right
1379
1380 else if( domn->pram->bcType == "WALL_OUT" ||
1381 (domn->pram->bcType=="WALL" && (domn->pram->vBClo !=0 || domn->pram->vBChi != 0)) ){
1382
1383 if(Ld < domn->pram->domainLength) {
1384 domn->posf->d.at(domn->ngrd) += domn->pram->domainLength - Ld;
1385 domn->pos->d.at(domn->ngrd-1) = 0.5*(domn->posf->d.at(domn->ngrd-1) + domn->posf->d.at(domn->ngrd));
1386 }
1387
1388 else if(Ld > domn->pram->domainLength) {
1389
1390 vector<double> cellFaces;
1391
1392 //before |----0---|----1---|-----2---------|------3-$----|--4---|---5----|
1393 //after |----0---|----1---|-----2---------|---3----$=4==|==5===|===6====|
1394 // or
1395 //before |----0---|----1---|-----2---------|------3------$--4---|---5----|
1396 //after |----0---|----1---|-----2---------|---3---------$==4===|===5====|
1397 // works if xSplitHi is at the far right face.
1398 double xSplitHi = domn->posf->d.at(0) + domn->pram->domainLength;
1399 double iSplitHi = domn->domainPositionToIndex(xSplitHi, false, 30);
1400 if(domn->posf->d.at(iSplitHi+1) != xSplitHi) {
1401 vector<double> cellFaces {domn->posf->d.at(iSplitHi), xSplitHi, domn->posf->d.at(iSplitHi+1)};
1402 splitCell(iSplitHi, 1, cellFaces);
1403 }
1404 for(int k=0; k<domn->v.size(); k++)
1405 domn->v.at(k)->d.erase(domn->v.at(k)->d.begin()+iSplitHi+1, domn->v.at(k)->d.end());
1406 domn->posf->d.push_back(xSplitHi);
1407 // pos is fine
1408 domn->ngrd -= (domn->ngrd - iSplitHi - 1);
1409 domn->ngrdf = domn->ngrd+1;
1410
1411 //------------- merge last cell if its small
1412
1413 if(domn->posf->d.at(domn->ngrd) - domn->posf->d.at(domn->ngrd-1) < domn->pram->dxmin) {
1414 merge2cells(domn->ngrd-2,false);
1415 }
1416 }
1417 } // endif WALL_OUT
1418
1419 else {
1420 cout << endl << "ERROR: meshManager::enforceDomainSize: not setup for given bcType" << endl;
1421 exit(0);
1422 }
1423
1424}
1425
1427
1432void meshManager::setGridDxc(const domain *line, vector<double> &dxc, double C) {
1433
1434 dxc.resize(line->posf->d.size()-1); // note: posf->d.size()-1 not ngrd due to merge2cells for posf kills face, then calls this func, ngrd is fixed after all vars are merged.
1435 double pm1;
1436 for(int i=0, ip=1; i<line->posf->d.size()-1; i++, ip++) {
1437 pm1 = line->posf->d.at(ip)*line->posf->d.at(i) < 0 ? -1.0 : 1.0; // handles cells that split x=0
1438 dxc.at(i) = abs(pow(abs(line->posf->d.at(ip)), C) -
1439 pm1*pow(abs(line->posf->d.at(i) ), C));
1440 }
1441}
1442
1444
1449void meshManager::setGridDx(const domain *line, vector<double> &dx) {
1450
1451 dx.resize(domn->posf->d.size()-1);
1452 for(int i=0, ip=1; i<dx.size(); i++, ip++)
1453 dx.at(i) = abs(domn->posf->d.at(ip) - domn->posf->d.at(i));
1454}
1455
1457
1462
1463 int imid = domn->domainPositionToIndex(0.0, true, 35);
1464
1465 double dxmid = domn->posf->d.at(imid+1) - domn->posf->d.at(imid);
1466 if(dxmid <= 3.0*domn->pram->dxmin) {
1467 if(imid < domn->ngrd-1)
1468 merge2cells(imid,true);
1469 if(imid > 0)
1470 merge2cells(imid-1,true);
1471 }
1472 return;
1473}
1474
1476
1482
1483 int iZero = domn->domainPositionToIndex(0.0, true, 32);
1484
1485 if(abs(domn->pos->d.at(iZero)) < 1.0E-10*domn->pram->dxmin)
1486 return; // cell is already symmetric
1487
1488 vector<double> splitFaces(3);
1489 double h;
1490 int iSplt;
1491 int nTimesToMerge;
1492
1493 if( abs(domn->posf->d.at(iZero)) > abs(domn->posf->d.at(iZero+1)) ) {
1494 // |----|----|------*---0--|---|---:--|
1495 // |<----h--->|
1496 // |<----h--->|<----h--->:
1497 // Split at ":"
1498
1499 h = abs(domn->posf->d.at(iZero));
1500 iSplt = domn->domainPositionToIndex(h, false, 33);
1501 if(domn->posf->d.at(iSplt+1) != h){
1502 splitFaces[0] = domn->posf->d.at(iSplt);
1503 splitFaces[1] = h;
1504 splitFaces[2] = domn->posf->d.at(iSplt+1);
1505 splitCell(iSplt, 1, splitFaces);
1506 }
1507 nTimesToMerge = iSplt - iZero;
1508 for(int i=1; i<=nTimesToMerge; i++)
1509 merge2cells(iZero, false);
1510
1511 }
1512 else {
1513 // |-:--|----|--0---*------|---|------|
1514 // |<----h--->|
1515 // :<----h--->|<----h--->|
1516 // Split at ":"
1517
1518 h = domn->posf->d.at(iZero+1);
1519 iSplt = domn->domainPositionToIndex(-h, true, 34);
1520 if(domn->posf->d.at(iSplt) != -h){
1521 splitFaces[0] = domn->posf->d.at(iSplt);
1522 splitFaces[1] = -h;
1523 splitFaces[2] = domn->posf->d.at(iSplt+1);
1524 splitCell(iSplt, 1, splitFaces);
1525 iZero++;
1526 iSplt++;
1527 }
1528 nTimesToMerge = iZero - iSplt;
1529 for(int i=1; i<=nTimesToMerge; i++)
1530 merge2cells(iSplt, false);
1531 }
1532
1533 return;
1534}
1535
1538// * Only for cylindrical or spherical
1539// */
1540//
1542
1543 if(domn->pram->xDomainCenter == 0.0) {
1544
1545 double h = 0.00254;
1546 int iSplitLo = domn->domainPositionToIndex((-1.0)*h/2.0, true, 56);
1547 int iSplitHi = domn->domainPositionToIndex(h/2.0, false, 56);
1548 int iSplitZero = domn->domainPositionToIndex(0.0, true, 56);
1549
1550 if(abs(domn->pos->d.at(iSplitZero)) > 1.0E-10) {
1551
1552 vector<double> cellFacesLo;
1553 vector<double> cellFacesHi;
1554
1555 if( domn->posf->d.at(iSplitHi+1) != h/2.0 ) {
1556 cellFacesHi.push_back(domn->posf->d.at(iSplitHi));
1557 cellFacesHi.push_back(h/2.0);
1558 cellFacesHi.push_back(domn->posf->d.at(iSplitHi+1));
1559 splitCell(iSplitHi, 1, cellFacesHi);
1560 }
1561
1562 if( domn->posf->d.at(iSplitLo) != (-1.0)*h/2.0 ) {
1563 cellFacesLo.push_back(domn->posf->d.at(iSplitLo));
1564 cellFacesLo.push_back((-1.0)*h/2.0);
1565 cellFacesLo.push_back(domn->posf->d.at(iSplitLo+1));
1566 splitCell(iSplitLo, 1, cellFacesLo);
1567 }
1568 else
1569 iSplitLo--;
1570
1571 while( abs(domn->posf->d.at(iSplitLo+1)) != abs(domn->posf->d.at(iSplitLo+2)) )
1572 merge2cells(iSplitLo+1, false);
1573
1574 merge2cells(iSplitLo-1, false);
1575 merge2cells(iSplitLo+1, false);
1576
1577 //iNextZero = iSplitLo+1;
1578 }
1579 //else
1580 //iNextZero = iSplitZero+1;
1581 //}
1582
1583 return;
1584 }
1585}
1586
1587
1589
1593void meshManager::setGridFromDxc(const vector<double> &dxc2) {
1594
1595 double C = domn->pram->cCoord;
1596 double invC = 1.0/domn->pram->cCoord;
1597
1598 //------------- Outflow on both sides
1599
1600 if(domn->pram->bcType=="OUTFLOW") {
1601
1602 //----------- for planar cases, expand/contract about the expansion/contraction "center"
1603 if(C==1 && !domn->pram->LplanarExpCent0) {
1604 double V2tot = accumulate(dxc2.begin(), dxc2.end(), 0.0);
1605 double dmb;
1606 domn->posf->d[0] = -pow(0.5*V2tot, invC);
1607 for(int ie=1, iw=0, i=0; ie<domn->ngrdf; ie++, iw++, i++) {
1608 if(domn->posf->d[iw] <= 0.0) {
1609 dmb = pow(abs(domn->posf->d[iw]),C) - dxc2[i];
1610 if(dmb >=0) domn->posf->d[ie] = -pow( dmb, invC);
1611 else domn->posf->d[ie] = pow(-dmb, invC);
1612 }
1613 else {
1614 domn->posf->d[ie] = pow(pow(domn->posf->d[iw],C) + dxc2[i], invC);
1615 }
1616 }
1617 }
1618
1619 //----------- for round cases, expand/contract about the r=0.0 point: FIX zero at zero
1620 else {
1621 int i0 = domn->domainPositionToIndex(0.0, true, 31);
1622 double pm1 = domn->posf->d.at(i0+1)*domn->posf->d.at(i0) < 0 ? -1.0 : 1.0; // handles cells that split x=0
1623 double dxc0 = abs( pow(abs(domn->posf->d.at(i0+1)), C) - pm1*pow(abs(domn->posf->d.at(i0) ), C) );
1624 double fracVolR = pow(domn->posf->d[i0+1],C) / dxc0;
1625 double fracVolL = 1.0 - fracVolR;
1626
1627 //-------- Right side of domain
1628
1629 domn->posf->d[i0+1] = pow(fracVolR*dxc2[i0], invC);
1630 for(int i=i0+2, im=i0+1; i<domn->ngrdf; i++, im++)
1631 domn->posf->d[i] = pow(pow(domn->posf->d[im],C) + dxc2[im], invC);
1632
1633 //-------- Left side of domain
1634
1635 domn->posf->d[i0] = -pow(fracVolL*dxc2[i0], invC);
1636 for(int i=i0-1, im=i0; i>=0; i--, im--)
1637 domn->posf->d[i] = -pow(pow(abs(domn->posf->d[im]),C) + dxc2[i], invC);
1638 }
1639 }
1640
1641 //------------------ Wall on left, outlet on right. Assume all posf values are >= 0.0, expand to the right.
1642
1643 else if(domn->pram->bcType == "WALL_OUT") {
1644
1645 domn->posf->d[0] = 0.0;
1646 for(int ie=1, iw=0, i=0; ie<domn->ngrdf; ie++, iw++, i++)
1647 domn->posf->d[ie] = pow(pow(domn->posf->d[iw],C) + dxc2[i], invC);
1648 }
1649
1650 //------------------
1651
1652 else {
1653 cout << endl << "ERROR: meshManager::setGridFromDxc: not setup for given bcType" << endl;
1654 exit(0);
1655 }
1656
1657 //------------------
1658
1659 domn->pos->setVar();
1660
1661 //------------------
1662}
1663
int ngrd
number of grid cells
Definition domain.h:42
int domainPositionToIndex(double position, const bool LowSide, int dbg)
Definition domain.cc:234
dv * uvel
Definition domain.h:51
double Ldomain()
Definition domain.cc:156
dv * phase
Definition domain.h:56
dv * posf
access as: posf->d[i], or posf->var_name, etc.
Definition domain.h:48
dv * pos
pointers to gas properties
Definition domain.h:47
int ngrdf
number of grid cell faces = ngrd+1
Definition domain.h:43
inputoutput * io
pointer to input/output object
Definition domain.h:72
eddy * ed
pointer to object for eddy operations
Definition domain.h:75
vector< dv * > v
All domain variables are stored in here.
Definition domain.h:45
param * pram
pointer to the parameters object
Definition domain.h:73
dv * rho
Definition domain.h:49
vector< double > d
the data
Definition dv.h:30
virtual void merge2cells(const int imrg, const double m2, const double m1, const bool LconstVolume=false)
Definition dv.cc:60
virtual void setVar(const int ipt=-1)
Definition dv.h:44
double rightEdge
right edge location of eddy
Definition eddy.h:32
double leftEdge
left edge location of eddy
Definition eddy.h:31
ostream * ostrm
Runtime: points to cout or to a file.
Definition inputoutput.h:33
void mergeSmallCells()
double calcDistance(const vector< double > &x, const vector< vector< double > > &y, vector< double > &sDist)
void set_iLower_iUpper()
void updateDA(const double &time, double &tLastDA, int &cLastDA, int iStart, int iEnd)
vector< double > dx
vector of cell sizes
Definition meshManager.h:41
void removeFaceNearZero()
vector< double > xnf
vector of new cell face positions
Definition meshManager.h:46
void interp1pt(const vector< double > &x, const vector< double > &y, const double &xval, double &yval, int &istart)
void makeCellWithZeroSymmetric()
void adaptEddyRegionOfMesh(const double &time, double &tLastDA, int &cLastDA)
vector< int > mark
dummy small cell index array for sorting
Definition meshManager.h:42
void setGridDx(const domain *line, vector< double > &dx)
void setGridFromDxc(const vector< double > &dxc2)
void init(domain *p_domn, const vector< dv * > p_phi)
int iUpper
region of grid to adapt (the cell w/ right eddy edge)
Definition meshManager.h:53
int iLower
region of grid to adapt (the cell w/ left eddy edge)
Definition meshManager.h:52
domain * domn
pointer to odt domain to adapt
Definition meshManager.h:37
void merge2cells(const int imrg, const bool LconstVolume=false)
vector< vector< double > > yf
vector of cell values
Definition meshManager.h:45
void mergeSmallCellsMP()
void splitCell(const int isplt, const int nsplt, const vector< double > &cellFaces)
int ngrdf
local number of grid faces
Definition meshManager.h:50
void impose2point5rule()
double posUpper
physical region of eddy (upper bound)
Definition meshManager.h:55
double posLower
physical region of eddy (lower bound)
Definition meshManager.h:54
int findPos(const vector< double > &x, const double val, const int &istart)
void setGridDxc(const domain *line, vector< double > &dxc, double C)
void splitCellWithZero()
‍** Create cell with r=0 at its center
int ngrd
local number of grid points
Definition meshManager.h:49
void adaptGrid(int iLower, int iUpper)
void adaptGrid_details(const int iLower, const int iUpper)
void setDxArray()
vector< double > lastDA
constant (unif) mesh to list time of last adapt
Definition meshManager.h:57
vector< double > xf
vector of cell face positions
Definition meshManager.h:44
vector< dv * > phi
vector of pointers to domainvariable objects
Definition meshManager.h:39
void adaptAfterSufficientDiffTime(const double &time, double &tLastDA, int &cLastDA, double &dtCUmax)
void interpVec(const vector< double > &x, const vector< double > &y, const vector< double > &xn, vector< double > &yn)
void fix2point5offender(const int mPos, const int &iglobal)
void enforceDomainSize()
double DAtimeFac
time until catch-up adaption is DAtimeFac * dtCUmax
Definition param.h:80
int cCoord
1 = planar, 2 = cylindrical, 3 = spherical
Definition param.h:68
bool LmultiPhase
true if domain has more than one phase (particles don't count)
Definition param.h:91
double dxmin
min grid spacing: = dxmin / domain length
Definition param.h:72
double vBChi
Dirichlet velocity boundary condition.
Definition param.h:97
bool LplanarExpCent0
flag: for planar cases (C=1) set the expansion center at 0 for outflow cases (normally expand about t...
Definition param.h:58
double domainLength
length of domain (m)
Definition param.h:34
bool Lspatial
spatial formulation if true
Definition param.h:62
bool Lperiodic
periodic if true
Definition param.h:61
double vBClo
Dirichlet velocity boundary condition.
Definition param.h:96
double gDens
grid density for mesher
Definition param.h:71
double xDomainCenter
position of the center of the domain
Definition param.h:69
double dxmax
max grid spacing = dxmax / domain length
Definition param.h:73
string bcType
OUTFLOW, PERIODIC, WALL, WALL_OUT.
Definition param.h:67
int sLastDA
size of the lastDA vector for timing adaptmesh after diff
Definition param.h:82
Header file for class domain.
Header file for class meshManager.
Header file for class param.