void EQS_KD2D::Validate( PROJECT* project, int np, NODE** node, int ne, NODE** cent, ELEM** elem ) { // ------------------------------------------------------------------------------------- // Check K and D for minmum flow velocity (Reynolds number) in surrounding nodes // define the limit of Re, where K and D will be set to their minimum double minRe = 10.0; // for each node: determine the maximum Reynolds number from surrounding nodes double* maxRe = (double*) MEMORY::memo.Array_nd( np ); for( int n=0; n<np; n++ ) { NODE* nd = node[n]; int no = nd->Getno(); double U = nd->v.U; double V = nd->v.V; double H = nd->v.S - nd->z; maxRe[no] = 4.0 * H * sqrt( U*U + V*V ) / project->vk; // check also surrounding nodes, if Reynolds number is too small at node ndi if( maxRe[no] < minRe ) { for( int j=0; j<nd->noel; j++ ) { ELEM* el = nd->el[j]; for( int k=0; k<el->Getncn(); k++ ) { NODE* ndk = el->Getnode(k); double U = ndk->v.U; double V = ndk->v.V; double H = ndk->v.S - ndk->z; double Re = H * 4.0 * sqrt( U*U + V*V ) / project->vk; if( Re > maxRe[no] ) { maxRe[no] = Re; if( maxRe[no] > minRe ) break; } } if( maxRe[no] > minRe ) break; } } } # ifdef _MPI_ project->subdom.Mpi_max( maxRe ); # endif for( int n=0; n<np; n++ ) { NODE* nd = node[n]; int no = nd->Getno(); // set the turbulence at nodes with very small Reynolds numbers to the minimum if( maxRe[no] < minRe ) { nd->v.K = project->minK; nd->v.D = project->minD; } } MEMORY::memo.Detach( maxRe ); if( quarterShape ) { for( int e=0; e<ne; e++ ) { ELEM* el = elem[e]; if( isFS( el->flag, ELEM::kRegion) && el->Getncn() == 4 ) { int no = el->Getno(); NODE* nd = cent[no]; double U = nd->v.U; double V = nd->v.V; double H = nd->v.S - nd->z; double c_maxRe = 4.0 * H * sqrt( U*U + V*V ) / project->vk; // check also surrounding nodes, if Reynolds number is too small at node ndi if( c_maxRe < minRe ) { for( int k=0; k<el->Getncn(); k++ ) { NODE* ndk = el->Getnode(k); double U = ndk->v.U; double V = ndk->v.V; double H = ndk->v.S - ndk->z; double Re = H * 4.0 * sqrt( U*U + V*V ) / project->vk; if( Re > c_maxRe ) { c_maxRe = Re; if( c_maxRe > minRe ) break; } } } // set the turbulence at nodes with very small Reynolds numbers to the minimum if( c_maxRe < minRe ) { nd->v.K = project->minK; nd->v.D = project->minD; } } } } // ------------------------------------------------------------------------------------- // try to interpolate nodes with negative values from surrounding nodes // Note: This interpolation is not so helpful in all cases. // ***PENDING*** MPI broadcasting of averaged nodal values Kave and Dave // from surrounding elements. /* GRID* rg = project->M2D->region; int* cnK = (int*) MEMORY::memo.Array_el( rg->Getne() ); int* cnD = (int*) MEMORY::memo.Array_el( rg->Getne() ); double* elK = (double*) MEMORY::memo.Array_el( rg->Getne() ); double* elD = (double*) MEMORY::memo.Array_el( rg->Getne() ); int iter; for( iter=0; iter<0; iter++ ) { int further = false; for( int e=0; e<rg->Getne(); e++ ) { ELEM* el = rg->Getelem(e); int no = el->Getno(); int ncn = el->getncn(); cnK[no] = cnD[no] = 0; elK[no] = elD[no] = 0.0; for( int i=0; i<ncn; i++ ) { NODE* nd = el->Getnode(i); if( isFS(nd->flag, NODE::kDry) ) continue; double K = nd->v.K; if( K > 0.0 ) { elK[no] += K; cnK[no]++; } double D = nd->v.D; if( D > 0.0 ) { elD[no] += D; cnD[no]++; } } } for( int n=0; n<np; n++ ) { NODE* nd = node[n]; if( nd->v.K <= 0.0 ) { further = true; int cntK = 0; double Kave = 0.0; for( int i=0; i<nd->noel; i++ ) { ELEM* el = nd->el[i]; int no = el->Getno(); if( cnK[no] ) { Kave += elK[no]; cntK += cnK[no]; } } if( cntK ) nd->v.K = Kave / cntK; } if( nd->v.D <= 0.0 ) { further = true; int cntD = 0; double Dave = 0.0; for( int i=0; i<nd->noel; i++ ) { ELEM* el = nd->el[i]; int no = el->Getno(); if( cnD[no] ) { Dave += elD[no]; cntD += cnD[no]; } } if( cntD ) nd->v.D = Dave / cntD; } } if( !further ) break; } MEMORY::memo.Detach( cnK ); MEMORY::memo.Detach( cnD ); MEMORY::memo.Detach( elK ); MEMORY::memo.Detach( elD ); if( iter ) { REPORT::rpt.Message( "\n%-25s%s %d %s\n", " (EQS_KD2D::Validate)", "interpolation of negative values in", iter, "iterations" ); } */ // ------------------------------------------------------------------------------------- // check K and D for minimum values for( int n=0; n<np; n++ ) { NODE* nd = node[n]; if( nd->v.K < project->minK || nd->v.D < project->minD ) { nd->v.K = project->minK; nd->v.D = project->minD; } } if( quarterShape ) { for( int e=0; e<ne; e++ ) { ELEM* el = elem[e]; if( isFS( el->flag, ELEM::kRegion) && el->Getncn() == 4 ) { int no = el->Getno(); NODE* nd = cent[no]; if( nd->v.K < project->minK || nd->v.D < project->minD ) { nd->v.K = project->minK; nd->v.D = project->minD; } } } } }
double* MODEL::Rot2D() { int np = region->Getnp(); int ne = region->Getne(); // ------------------------------------------------------------------------------------- // allocate memory for rotation of flow field // ------------------------------------------------------------------------------------- double* rot = (double*) MEMORY::memo.Array_nd( np ); double* wgt = (double*) MEMORY::memo.Array_nd( np ); for( int n=0; n<np; n++ ) rot[n] = wgt[n] = 0.0; // ------------------------------------------------------------------------------------- // loop on elements // ------------------------------------------------------------------------------------- for( int e=0; e<ne; e++ ) { ELEM* elem = region->Getelem(e); SHAPE* shape = elem->GetQShape(); int ngp = shape->ngp; // number of GAUSS points int nnd = shape->nnd; // number of corner nodes // ----------------------------------------------------------------------------------- // compute coordinates relative to first node double x[kMaxNodes2D], y[kMaxNodes2D]; x[0] = elem->nd[0]->x; y[0] = elem->nd[0]->y; for( int i=1; i<nnd; i++ ) { x[i] = elem->nd[i]->x - *x; y[i] = elem->nd[i]->y - *y; } x[0] = y[0] = 0.0; // ----------------------------------------------------------------------------------- // use GAUSS point integration to solve momentum and continuity for( int g=0; g<ngp; g++ ) { // form JACOBIAN transformation matrix --------------------------------------------- double trafo[2][2]; double* dfdxPtr = shape->dfdx[g]; double* dfdyPtr = shape->dfdy[g]; double detj = shape->jacobi2D( nnd, dfdxPtr, dfdyPtr, x, y, trafo ); double weight = detj * shape->weight[g]; // compute values of shape functions at GP g --------------------------------------- double* n = shape->f[g]; double dndx[kMaxNodes2D], dndy[kMaxNodes2D]; for( int i=0; i<nnd; i++ ) { dndx[i] = trafo[0][0] * dfdxPtr[i] + trafo[0][1] * dfdyPtr[i]; dndy[i] = trafo[1][0] * dfdxPtr[i] + trafo[1][1] * dfdyPtr[i]; } // compute flow parameters and their derivatives ----------------------------------- double dUdy = 0.0; double dVdx = 0.0; for( int i=0; i<nnd; i++ ) { NODE* node = elem->nd[i]; dUdy += dndy[i] * node->v.U; dVdx += dndx[i] * node->v.V; } // compute rotation ---------------------------------------------------------------- double f = weight * ( dVdx - dUdy ); for( int i=0; i<nnd; i++ ) { NODE* nd = elem->nd[i]; int no = nd->Getno(); rot[no] += f; wgt[no] += weight; } } } subdom->Mpi_assemble( rot ); subdom->Mpi_assemble( wgt ); // ------------------------------------------------------------------------------------- // solve for rotation for( int n=0; n<np; n++ ) { rot[n] /= wgt[n]; } // ------------------------------------------------------------------------------------- MEMORY::memo.Detach( wgt ); return rot; }
void MODEL::MPI_Comm_Dry( PROJECT* project, int initialize ) { # ifdef _MPI_ DRYREW* dryRew = ®ion->dryRew; SUBDOM* subdom = &project->subdom; INFACE* inface = subdom->inface; // loop on all interfaces: exchange dry flag ----------------------------------------------------- // set sub->dry flag for dry interface nodes in adjacent subdomains for( int s=0; s<subdom->npr; s++ ) { MPI_Status status; int np = inface[s].np; if( np > 0 ) { // initialize the flag "nd->sub->dry" -------------------------------------------------------- for( int n=0; n<np; n++ ) { NODE* nd = inface[s].node[n]; SUB* sub = nd->sub; while( sub ) { if( sub->no == s ) sub->dry = false; sub = sub->next; } if( isFS(nd->flag, NODE::kDry) ) inface[s].sia1[n] = true; else inface[s].sia1[n] = false; } // exchange data on interface nodes ---------------------------------------------------------- MPI_Sendrecv( inface[s].sia1, np, MPI_CHAR, s, 1, inface[s].ria1, np, MPI_CHAR, s, 1, MPI_COMM_WORLD, &status ); // set the flag "nd->sub->dry" for dry nodes in adjacent subdomain and ----------------------- // adjust water elevation (necessary for just wetted interface nodes) for( int n=0; n<np; n++ ) { NODE* nd = inface[s].node[n]; if( inface[s].ria1[n] ) { SUB* sub = nd->sub; while( sub ) { if( sub->no == s ) sub->dry = true; sub = sub->next; } } } } } // average data across domains (necessary for wetting interfaces) -------------------------------- if( initialize ) { MPI_Status status; int rgnp = region->Getnp(); int* cnt = (int*) MEMORY::memo.Array_nd( rgnp ); for( int n=0; n<rgnp; n++ ) cnt[n] = 1; for( int s=0; s<subdom->npr; s++ ) { int npinf = inface[s].np; if( npinf > 0 ) { for( int n=0; n<npinf; n++ ) { NODE* nd = inface[s].node[n]; inface[s].send[3*n] = nd->v.U; inface[s].send[3*n+1] = nd->v.V; inface[s].send[3*n+2] = nd->v.S; } } } for( int s=0; s<subdom->npr; s++ ) { int npinf = inface[s].np; if( npinf > 0 ) { MPI_Sendrecv( inface[s].send, 3*npinf, MPI_DOUBLE, s, 1, inface[s].recv, 3*npinf, MPI_DOUBLE, s, 1, MPI_COMM_WORLD, &status ); for( int n=0; n<npinf; n++ ) { NODE* nd = inface[s].node[n]; SUB* sub = nd->sub; while( sub ) { if( sub->no == s ) { if( !sub->dry ) { nd->v.U += inface[s].recv[3*n]; nd->v.V += inface[s].recv[3*n+1]; nd->v.S += inface[s].recv[3*n+2]; cnt[nd->Getno()]++; } } sub = sub->next; } } } } for( int n=0; n<rgnp; n++ ) { if( cnt[n] > 1 ) { NODE* nd = region->Getnode(n); nd->v.U /= cnt[n]; nd->v.V /= cnt[n]; nd->v.S /= cnt[n]; } } MEMORY::memo.Detach( cnt ); } # ifdef kDebug_2 { char text[200]; sprintf( text, "### DEBUGGING: List of dry interface nodes...\n\n" ); REPORT::rpt.Output( text, 1 ); for( int s=0; s<subdom->npr; s++ ) { int np = inface[s].np; if( np > 0 ) { sprintf( text, "interface to domain %d\n", s+1 ); REPORT::rpt.Output( text, 1 ); for( int n=0; n<np; n++ ) { NODE* nd = inface[s].node[n]; SUB* sub = nd->sub; while( sub ) { if( sub->no == s ) { if( sub->dry ) { if( isFS(nd->flag, NODE::kDry) ) { sprintf( text, "dry interface node %5d: dry\n", nd->Getname() ); REPORT::rpt.Output( text, 1 ); } else { sprintf( text, "wet interface node %5d: dry\n", nd->Getname() ); REPORT::rpt.Output( text, 1 ); } } else { if( isFS(nd->flag, NODE::kDry) ) { sprintf( text, "dry interface node %5d: wet\n", nd->Getname() ); REPORT::rpt.Output( text, 1 ); } else { sprintf( text, "wet interface node %5d: wet\n", nd->Getname() ); REPORT::rpt.Output( text, 1 ); } } } sub = sub->next; } } } } } # endif // #ifdef kDebug_2 # endif // #ifdef _MPI_ }
void EQS_D2D::Validate( int np, NODE** node, PROJECT* project ) { // for( int iter=0; iter<1000; iter++ ) // { // int further = false; // // for( int i=0; i<np; i++ ) // { // NODE* nd = node[i]; // // if( isFS(nd->flag, NODE::kDry) ) continue; // // double U = nd->v.U; // double V = nd->v.V; // double Us = sqrt( nd->cf * (U*U + V*V) ); // // double H = nd->v.S - nd->z; // if( H <= 0.0 ) H = project->hmin; // // if( nd->v.D <= 0.0 ) // { // further = true; // // int noel = nd->noel; // // double Dave = 0.0; // int cntD = 0; // // for( int j=0; j<noel; j++ ) // { // ELEM* el = nd->el[j]; // // for( int k=0; k<el->getnnd(); k++ ) // { // double D = el->nd[k]->v.D; // if( D > 0.0 ) // { // Dave += D; // cntD++; // } // } // } // // // ***PENDING*** MPI broadcasting of averaged values ... // // if( cntD > 0 ) // { // nd->v.D = Dave / cntD; // } // } // } // // if( !further ) break; // } // ------------------------------------------------------------------------------------- for( int i=0; i<np; i++ ) { NODE* nd = node[i]; int no = nd->Getno(); if( isFS(nd->flag, NODE::kDry) ) continue; if( nd->v.D < project->minD ) { nd->v.K = project->minK; nd->v.D = project->minD; } } }
int REORDER::removeFront( ELEM *el, REOFRONT **frnt, int num ) { int i, ncn; ncn = el->Getncn(); el->mark = false; for( i=0; i<ncn; i++ ) { NODE *nd; REOFRONT *fr, *fr_prev; nd = el->nd[i]; fr = *frnt; fr_prev = NULL; while( fr ) { if( fr->node == nd ) break; fr_prev = fr; fr = fr->next; } // wenn der Knoten in der Liste steht ... if( fr ) { fr->miss++; if( fr->miss == nd->noel ) { // Knoten war mit dem Element 'el' neu hinzugekommen // und kann nun wieder entfernt werden num--; if( fr_prev ) fr_prev->next = fr->next; else *frnt = fr->next; } } // ... andernfalls wird er nun wieder aktiv else { if( nd->noel > 1 ) { fr = &frontPtr[nd->Getno()]; if( fr_prev ) fr_prev->next = fr; else *frnt = fr; fr->next = NULL; fr->miss = 1; num++; } } } return num; }
int REORDER::updateFront( ELEM *el, REOFRONT **frnt, int num, int histflg ) { int i, ncn; ncn = el->Getncn(); el->mark = true; for( i=0; i<ncn; i++ ) { NODE *nd; REOFRONT *fr, *fr_prev; nd = el->nd[i]; fr = *frnt; fr_prev = NULL; while( fr ) { if( fr->node == nd ) break; fr_prev = fr; fr = fr->next; } // wenn der Knoten bereits in der Liste steht ... if ( fr ) { fr->miss--; if ( !fr->miss ) { // Knoten ist mit dem Element 'el' komplett und // wird aus der Liste aktiver Knoten entfernt num--; if (histflg) fr->hist = 0; if (fr_prev) fr_prev->next = fr->next; else *frnt = fr->next; } } // ... andernfalls wird er an die Liste angehaengt else { if( nd->noel > 1) { fr = &frontPtr[nd->Getno()]; if( fr_prev ) fr_prev->next = fr; else *frnt = fr; fr->next = NULL; fr->miss = nd->noel - 1; if( histflg ) fr->hist = hist_cnt++; num++; } } } return (num); }