void PRECO_ILUT::Factor( PROJECT* project, EQS* eqs, CRSMAT* crsm ) { REPORT::rpt.Message( 2, "\n (PRECO_ILUT::Factor) preconditioning: ILUT\n" ); //////////////////////////////////////////////////////////////////////////////////////// // 1. initializations and memory allocation int* width = crsm->m_width; int** index = crsm->m_index; REALPR** A = crsm->m_A; //int* Iw = crsi->m_width; //int** Ii = crsi->m_index; REALPR** ILU = crsi->m_A; int ceq = crsi->m_ceq; int neq = crsm->m_neq; int neq_dn = crsm->m_neq_dn; int neq_up = crsm->m_neq_up; //for( int e=0; e<neq; e++ ) Iw[e] = 1; //crsi->Init(); // allocate dynamic front memory ------------------------------------------------------- int mfw = 4 * ceq; fromat = new FROMAT( mfw, neq ); if( !fromat ) REPORT::rpt.Error( kMemoryFault, "can not allocate memory - PRECO_ILUT::Factor(1)" ); //////////////////////////////////////////////////////////////////////////////////////// // 2. LU factorization // // 2.1 MPI: incomplete LU factorization restricted to interior subdomain nodes # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Factor) starting with 2.1\n" ); # endif int maximumFW = 0; for( int e=0; e<neq_up; e++ ) { if( fabs(A[e][0]) < kMinPivot ) { REPORT::rpt.Error( kParameterFault, "%s - PRECO_ILUT::Factor(2)", "factorization can not be applied to the matrix" ); } // equation "e" is elimination equation ---------------------------------------------- fromat->Insert( e, width, index, A ); if( fromat->m_actFW > maximumFW ) maximumFW = fromat->m_actFW; # ifdef kEqCounter if( ((e+1)%1000) == 0 ) { REPORT::rpt.Screen( 2, "\r (PRECO_ILUT::Factor) %d (maximum FW = %d)", e+1, maximumFW ); } # endif fromat->Eliminate( e ); ILU[e][0] = (REALPR) fromat->m_U[fromat->m_actFW]; // diagonal element //if( fabs(ILU[e][0]) < kZero ) //{ // REPORT::rpt.Error( kParameterFault, "%s - PRECO_ILUT::Factor(2)", // "factorization can not be applied to the matrix" ); //} for( int i=1; i<width[e]; i++ ) { int f = index[e][i]; int j = fromat->m_eql[f].ind; if( f > e ) { ILU[e][i] = (REALPR) fromat->m_U[j]; for( int k=1; k<width[f]; k++ ) { if( index[f][k] == e ) { ILU[f][k] = (REALPR) fromat->m_L[j]; break; } } } } //fromat->Sort(); //Ii[e][0] = e; //ILU[e][0] = (REALPR) fromat->m_eqtr[fromat->m_actFW].U; //EQTREE* eqtr = (EQTREE*) fromat->m_root.First(); //while( eqtr ) //{ // int i; // int f = eqtr->e; // i = Iw[e]; // Ii[e][i] = f; // ILU[e][i] = (REALPR) eqtr->U; // Iw[e]++; // i = Iw[f]; // Ii[f][i] = e; // ILU[f][i] = (REALPR) eqtr->L; // Iw[f]++; // if( Iw[e] >= ceq || Iw[f] >= ceq/2 ) break; // eqtr = (EQTREE*) eqtr->Next(); //} // ... } //////////////////////////////////////////////////////////////////////////////////////// // 2.2 MPI communication: // receive interface equations from subdomains with smaller pid (2 <- 1) // s < pid ==> upstream interface nodes //# ifdef _MPI_DBG // REPORT::rpt.Output( " (PRECO_ILUT::Factor) starting with 2.2\n" ); //# endif # ifdef _MPI_ if( project->subdom.npr > 1 ) { SUBDOM* subdom = &project->subdom; INFACE* inface = subdom->inface; MPI_Status status; int df = eqs->dfcn; for( int s=subdom->npr-1; s>=0; s-- ) { int np = inface[s].np; // number of interface nodes if( np > 0 && s < subdom->pid ) // upstream interface nodes { for( int n=0; n<np; n++ ) { NODE* ndr = inface[s].node[n]; if( !isFS(ndr->flag, NODE::kDry) ) // nothing to do if node is dry... { SUB* subr = ndr->sub; while( subr ) { if( subr->no == s ) break; subr = subr->next; } if( !subr->dry ) // ...or if the node is dry in { // any adjacent subdomain for( int e=0; e<df; e++ ) { int req = eqs->GetEqno( ndr, e ); if( req >= 0 ) { int cnt; MPI_Recv( &cnt, 1, MPI_INT, s, 1, MPI_COMM_WORLD, &status ); if( cnt ) { MPI_Recv( inface[s].ria1, cnt, MPI_CHAR, s, 2, MPI_COMM_WORLD, &status ); MPI_Recv( inface[s].ria2, cnt, MPI_INT, s, 3, MPI_COMM_WORLD, &status ); MPI_Recv( inface[s].recv, cnt, MPI_DOUBLE, s, 4, MPI_COMM_WORLD, &status ); for( int j=0; j<cnt; j++ ) { int eid = inface[s].ria1[j]; int name = inface[s].ria2[j]; NODE* ndc = subdom->node[name - 1]; if( ndc ) { int ceq = eqs->GetEqno( ndc, eid ); for( int c=0; c<width[req]; c++ ) { if( index[req][c] == ceq ) { ILU[req][c] += (REALPR)inface[s].recv[j]; break; } } } } } } } } } } } } } //////////////////////////////////////////////////////////////////////////////////////// // 2.3 MPI: factorization of interface nodes //# ifdef _MPI_DBG // REPORT::rpt.Output( " (PRECO_ILUT::Factor) starting with 2.3\n" ); //# endif for( int e=neq_up; e<neq_dn; e++ ) { if( fabs(ILU[e][0]) < kMinPivot ) { int piv = -1; double max = 0.0; for( int j=1; j<width[e]; j++ ) { int eq = index[e][j]; if( eq > e ) { // find column "e" in equation "eq" -------------------------------------------- for( int k=0; k<width[eq]; k++ ) { if( index[eq][k] == e ) { double p = fabs( ILU[eq][k] ); if( p > max ) { piv = eq; max = p; } } } } } if( piv > 0 ) { for( int j=0; j<width[e]; j++ ) { for( int k=0; k<width[piv]; k++ ) { if( index[e][j] == index[piv][k] ) ILU[e][j] += ILU[piv][k]; } } } else { REPORT::rpt.Error( kParameterFault, "ILU-Factorization cannot be applied to the matrix" ); } } // equation "e" is elimination equation ---------------------------------------------- for( int j=1; j<width[e]; j++ ) { int eq = index[e][j]; if( eq > e )// && eq > neq_dn ) // Note: The elimination of just received upstream { // equations (2.2) was performed in prior subdomain double factor = 0.0; // find column "e" in equation "eq" and compute elimination factor --------------- int k; for( k=0; k<width[eq]; k++ ) { if( index[eq][k] == e ) { factor = -ILU[eq][k] / ILU[e][0]; break; } } // save elimination factor (L-Matrix: index[eq][k] == e < eq) -------------------- ILU[eq][k] = (REALPR)factor; // add elimination equation ILU[i] to ILU[eq] ------------------------------------ for( k=1; k<width[e]; k++ ) { if( index[e][k] >= e ) { for( int l=0; l<width[eq]; l++ ) { if( index[eq][l] == index[e][k] ) { ILU[eq][l] += (REALPR)factor * ILU[e][k]; break; } } } } } } } //////////////////////////////////////////////////////////////////////////////////////// // 2.4 MPI communication: // send to subdomain with larger pid (2 -> 3) // s > pid ==> downstream interface nodes //# ifdef _MPI_DBG // REPORT::rpt.Output( " (PRECO_ILUT::Factor) starting with 2.4\n" ); //# endif if( project->subdom.npr > 1 ) { SUBDOM* subdom = &project->subdom; INFACE* inface = subdom->inface; int df = eqs->dfcn; for( int s=0; s<subdom->npr; s++ ) { int np = inface[s].np; // number of interface nodes if( np > 0 && s > subdom->pid ) // downstream interface nodes { for( int n=0; n<np; n++ ) { NODE* ndr = inface[s].node[n]; if( !isFS(ndr->flag, NODE::kDry) ) // nothing to send if the node is dry... { SUB* subr = ndr->sub; while( subr ) { if( subr->no == s ) break; subr = subr->next; } if( !subr->dry ) // ...or if the node is dry in { // any adjacent subdomain for( int e=0; e<df; e++ ) { int req = eqs->GetEqno( ndr, e ); if( req >= 0 ) { int cnt = 0; for( int c=0; c<width[req]; c++ ) { int ceq = index[req][c]; NODE* ndc = eqs->eqnoNode[ceq]; int eid = eqs->eqid[ceq]; // is ndc a point on interface "s"? SUB* subc = ndc->sub; while( subc ) { if( subc->no == s ) break; subc = subc->next; } if( subc ) { inface[s].sia1[cnt] = eid; inface[s].sia2[cnt] = ndc->Getname(); inface[s].send[cnt] = ILU[req][c]; cnt++; } } MPI_Send( &cnt, 1, MPI_INT, s, 1, MPI_COMM_WORLD ); if( cnt ) { MPI_Send( inface[s].sia1, cnt, MPI_CHAR, s, 2, MPI_COMM_WORLD ); MPI_Send( inface[s].sia2, cnt, MPI_INT, s, 3, MPI_COMM_WORLD ); MPI_Send( inface[s].send, cnt, MPI_DOUBLE, s, 4, MPI_COMM_WORLD ); } } } } } } } } } # endif //////////////////////////////////////////////////////////////////////////////////////// # ifdef kDebug { char filename[80]; if( project->subdom.npr == 1 ) sprintf( filename, "ilu_2.4.dbg" ); else sprintf( filename, "ilu_2.4_%02d.dbg", project->subdom.pid+1 ); eqs->ExportEQS( filename, crsi, project ); } # endif //# ifdef _MPI_DBG // REPORT::rpt.Output( " (PRECO_ILUT::Factor) ILU factorization finished\n" ); //# endif }
void MODEL::DoDryRewet( PROJECT* project, int* dried, int* wetted ) { DRYREW *dryRew = ®ion->dryRew; region->Connection( 0L ); int del = 0; int wel = 0; if( dryRew->method == 1 ) { // mark nodes and elements to be rewetted ------------------------------------------------------ wel = region->Rewet( dryRew->rewetLimit, dryRew->rewetPasses, project ); // mark dry nodes and elements ----------------------------------------------------------------- del = region->Dry( dryRew->dryLimit, dryRew->countDown ); } else if( dryRew->method == 2 ) { region->DryRewet( dryRew->dryLimit, dryRew->rewetLimit, dryRew->countDown, &del, &wel ); } else if( dryRew->method == 3 ) { region->RewetDry( dryRew->dryLimit, dryRew->rewetLimit, dryRew->countDown, &del, &wel ); } /* // future work ... else if( dryRew->method == 4 ) { // determine dynamic boundary ------------------------------------------------------------------ region.DynamicBound( np, node, *elem, dryRew->dryLimit, project ); } */ ////////////////////////////////////////////////////////////////////////////////////////////////// # ifdef _MPI_ del = project->subdom.Mpi_sum( del ); wel = project->subdom.Mpi_sum( wel ); # endif char text [200]; sprintf( text, "\n (MODEL::DoDryRewet) %d elements have got dry\n", del ); REPORT::rpt.Output( text, 3 ); sprintf( text, "\n (MODEL::DoDryRewet) %d elements have got wet\n", wel ); REPORT::rpt.Output( text, 3 ); int dryRewFlag = del + wel; if( dryRewFlag ) { //////////////////////////////////////////////////////////////////////////////////////////////// // exchange information on dry nodes on interfaces # ifdef _MPI_ if( project->subdom.npr > 1 ) { MPI_Comm_Dry( project, true ); ////////////////////////////////////////////////////////////////////////////////////////////// // reset wetted area, in case of dry nodes that are not dry in adjacent subdomains // added on 20.04.2006, sc if( dryRew->method == 2 || dryRew->method == 3 ) { int wetted = 0; for( int n=0; n<region->Getnp(); n++ ) { NODE* nd = region->Getnode(n); nd->mark = false; double H = nd->v.S - nd->zor; if( H < dryRew->dryLimit ) { SF( nd->flag, NODE::kDry ); } else if( isFS(nd->flag, NODE::kDry) ) { nd->mark = true; CF( nd->flag, NODE::kDry ); wetted++; } CF( nd->flag, NODE::kMarsh ); nd->z = nd->zor; } if( dryRew->method == 2 ) { region->DryRewet( dryRew->dryLimit, dryRew->rewetLimit, dryRew->countDown, &del, &wel ); } else if( dryRew->method == 3 ) { region->RewetDry( dryRew->dryLimit, dryRew->rewetLimit, dryRew->countDown, &del, &wel ); } //////////////////////////////////////////////////////////////////////////////////////////// MPI_Comm_Dry( project, false ); wetted = project->subdom.Mpi_sum( wetted ); sprintf( text, "\n (MODEL::DoDryRewet) %d interface nodes have got wet\n", wetted ); REPORT::rpt.Output( text, 3 ); } } //////////////////////////////////////////////////////////////////////////////////////////////// // reset interface flags: kInface, kInface_DN and kInface_UP; this is // necessary for the correct ordering of equations in EQS::ResetEqOrder() project->subdom.SetInface( region ); # endif // #ifdef _MPI_ //////////////////////////////////////////////////////////////////////////////////////////////// // determine 1D boundary elements and ---------------------------------------------------------- // set up slip velocity boundary conditions Initialize(); SetNormal(); SetRotation(); region->SetSlipFlow(); REPORT::rpt.PrintTime( 3 ); // ================================================================================================ # ifdef kDebug_1 for( int n=0; n<region->Getnp(); n++ ) { NODE* ndbg = region->Getnode(n); switch( ndbg->Getname() ) { case 3654: REPORT::rpt.Message( "\n" ); REPORT::rpt.Message( "### NODE %6d: inface = %d\n", ndbg->Getname(), ndbg->flag&NODE::kInface ); REPORT::rpt.Message( "### : inface_dn = %d\n", ndbg->flag&NODE::kInface_DN ); REPORT::rpt.Message( "### : inface_up = %d\n", ndbg->flag&NODE::kInface_UP ); REPORT::rpt.Message( "\n" ); REPORT::rpt.Message( "### : dry = %d\n", ndbg->flag&NODE::kDry ); REPORT::rpt.Message( "### : marsh = %d\n", ndbg->flag&NODE::kMarsh ); REPORT::rpt.Message( "### : H = %f\n", ndbg->v.S - ndbg->zor ); REPORT::rpt.Message( "\n" ); REPORT::rpt.Message( "### : bound = %d\n", ndbg->flag&NODE::kBound ); REPORT::rpt.Message( "### : inflow = %d\n", ndbg->flag&NODE::kInlet ); REPORT::rpt.Message( "### : outflow = %d\n", ndbg->flag&NODE::kOutlet ); REPORT::rpt.Message( "### : rotat = %d\n", ndbg->flag&NODE::kRotat ); REPORT::rpt.Message( "### : noMoment = %d\n", ndbg->flag&NODE::kNoMoment ); REPORT::rpt.Message( "\n" ); REPORT::rpt.Message( "### : countDown = %d\n", ndbg->countDown ); { SUB* sub = ndbg->sub; while( sub ) { REPORT::rpt.Message( "### SUBDOM %4d: dry = %d\n", sub->no+1, sub->dry ); sub = sub->next; } } break; } } # endif // ================================================================================================ } else { // set up structure for connection of nodes to elements ---------------------------------------- // dry elements are not taken into consideration region->Connection( ELEM::kDry ); } if( dried ) *dried = del; if( wetted ) *wetted = wel; region->firstDryRew = false; }
void PRECO_ILUT::Solve( PROJECT* project, EQS* eqs, double* B, double* X ) { int neq = crsi->m_neq; int neq_dn = crsi->m_neq_dn; int neq_up = crsi->m_neq_up; int* width = crsi->m_width; int** index = crsi->m_index; REALPR** ILU = crsi->m_A; //////////////////////////////////////////////////////////////////////////////////////// // 1. forward solve: manipulate vector B with lower part of matrix ILU // // 1.1 MPI: forward solve for interior subdomain nodes # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Solve) starting with 1.1\n" ); # endif for( int i=0; i<neq_up; i++ ) { X[i] = B[i]; for( int j=1; j<width[i]; j++ ) { int eq = index[i][j]; if( eq < i ) // L-matrix { X[i] += ILU[i][j] * X[eq]; } } } //////////////////////////////////////////////////////////////////////////////////////// // 1.2 MPI communication: // receive from subdomains with smaller pid (2 <- 1) // s < pid ==> upstream interface nodes # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Solve) starting with 1.2\n" ); # endif # ifdef _MPI_ if( project->subdom.npr > 1 ) { SUBDOM* subdom = &project->subdom; INFACE* inface = subdom->inface; MPI_Status status; int df = eqs->dfcn; for( int s=subdom->npr-1; s>=0; s-- ) { int np = inface[s].np; // number of interface nodes if( np > 0 && s < subdom->pid ) // upstream interface nodes { int cnt = 0; # ifdef _MPI_DBG { char text[200]; sprintf( text, " ### receiving from %d:", s+1 ); REPORT::rpt.Output( text ); } # endif MPI_Recv( &cnt, 1, MPI_INT, s, 1, MPI_COMM_WORLD, &status ); # ifdef _MPI_DBG { char text[200]; sprintf( text, " %d values\n", cnt ); REPORT::rpt.Output( text ); } # endif if( cnt ) { MPI_Recv( inface[s].recv, cnt, MPI_DOUBLE, s, 2, MPI_COMM_WORLD, &status ); cnt = 0; for( int n=0; n<np; n++ ) { NODE* nd = inface[s].node[n]; if( !isFS(nd->flag, NODE::kDry) ) // nothing received if node is dry... { SUB* sub = nd->sub; while( sub ) { if( sub->no == s ) break; sub = sub->next; } if( !sub->dry ) // ...or if the node is dry in { // any adjacent subdomain for( int e=0; e<df; e++ ) { int eqno = eqs->GetEqno( nd, e ); if( eqno >= 0 ) { X[eqno] = inface[s].recv[cnt]; cnt++; } } } } } } } } } //////////////////////////////////////////////////////////////////////////////////////// // 1.3 MPI: forward solve for upstream interface nodes // Note: X[i] is not initialized with B[i] since // this was performed in prior subdomain # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Solve) starting with 1.3\n" ); # endif for( int i=neq_up; i<neq_dn; i++ ) { for( int j=1; j<width[i]; j++ ) { int eq = index[i][j]; if( eq < i ) { X[i] += ILU[i][j] * X[eq]; } } } //////////////////////////////////////////////////////////////////////////////////////// // 1.4 MPI: faktorisation of downstream interface nodes # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Solve) starting with 1.4\n" ); # endif for( int i=neq_dn; i<neq; i++ ) { X[i] = B[i]; for( int j=1; j<width[i]; j++ ) { int eq = index[i][j]; if( eq < neq_dn ) { X[i] += ILU[i][j] * X[eq]; } } } //////////////////////////////////////////////////////////////////////////////////////// // 1.5 MPI communication: // send to subdomains with larger pid (2 -> 3) // s > pid ==> downstream interface nodes # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Solve) starting with 1.5\n" ); # endif if( project->subdom.npr > 1 ) { SUBDOM* subdom = &project->subdom; INFACE* inface = subdom->inface; int df = eqs->dfcn; for( int s=0; s<subdom->npr; s++ ) { int np = inface[s].np; // number of interface nodes if( np > 0 && s > subdom->pid ) // downstream interface nodes { int cnt = 0; for( int n=0; n<np; n++ ) { NODE* nd = inface[s].node[n]; if( !isFS(nd->flag, NODE::kDry) ) // nothing to send if the node is dry... { SUB* sub = nd->sub; while( sub ) { if( sub->no == s ) break; sub = sub->next; } if( !sub->dry ) // ...or if the node is dry in { // any adjacent subdomain for( int e=0; e<df; e++ ) { int eqno = eqs->GetEqno( nd, e ); if( eqno >= 0 ) { inface[s].send[cnt] = X[eqno]; cnt++; } } } } } # ifdef _MPI_DBG { char text[200]; sprintf( text, " ### sending %d values to %d\n", cnt, s+1 ); REPORT::rpt.Output( text ); } # endif MPI_Send( &cnt, 1, MPI_INT, s, 1, MPI_COMM_WORLD ); if( cnt ) MPI_Send( inface[s].send, cnt, MPI_DOUBLE, s, 2, MPI_COMM_WORLD ); } } } # endif //////////////////////////////////////////////////////////////////////////////////////// # ifdef kDebug { FILE* dbg; char filename[80]; MODEL* model = project->M2D; GRID* region = model->region; if( project->subdom.npr == 1 ) sprintf( filename, "forwX.dbg" ); else sprintf( filename, "forwX_%02d.dbg", project->subdom.pid ); dbg = fopen( filename, "w" ); fprintf( dbg, "%d\n", region->Getnp() ); for( int n=0; n<region->Getnp(); n++ ) { NODE* nd = region->Getnode( n ); for( int e=0; e<eqs->dfcn; e++ ) { int eqno = eqs->GetEqno( nd, e ); fprintf( dbg, "%5d %1d ", nd->Getname(), e ); if( eqno >= 0 ) fprintf( dbg, "%14.6le\n", X[eqno] ); else fprintf( dbg, "%14.6le\n", 0.0 ); } } fclose( dbg ); } # endif # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Solve) forward solve finished\n" ); # endif //////////////////////////////////////////////////////////////////////////////////////// // 2. solve for X with upper part of matrix ILU (backward substitution) // // 2.1 MPI communication: // receive from subdomains with larger pid (2 <- 3) // s > pid ==> downstream interface nodes # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Solve) starting with 2.1\n" ); # endif # ifdef _MPI_ if( project->subdom.npr > 1 ) { SUBDOM* subdom = &project->subdom; INFACE* inface = subdom->inface; MPI_Status status; int df = eqs->dfcn; for( int s=subdom->npr-1; s>=0; s-- ) { int np = inface[s].np; // number of interface nodes if( np > 0 && s > subdom->pid ) // downstream interface nodes { int cnt = 0; # ifdef _MPI_DBG { char text[200]; sprintf( text, " ### receiving from %d:", s+1 ); REPORT::rpt.Output( text ); } # endif MPI_Recv( &cnt, 1, MPI_INT, s, 1, MPI_COMM_WORLD, &status ); # ifdef _MPI_DBG { char text[200]; sprintf( text, " %d values\n", cnt ); REPORT::rpt.Output( text ); } # endif if( cnt ) { MPI_Recv( inface[s].recv, cnt, MPI_DOUBLE, s, 2, MPI_COMM_WORLD, &status ); cnt = 0; for( int n=0; n<np; n++ ) { NODE* nd = inface[s].node[n]; if( !isFS(nd->flag, NODE::kDry) ) // nothing received if node is dry... { SUB* sub = nd->sub; while( sub ) { if( sub->no == s ) break; sub = sub->next; } if( !sub->dry ) // ...or if the node is dry in { // any adjacent subdomain for( int e=0; e<df; e++ ) { int req = eqs->GetEqno( nd, e ); if( req >= 0 ) { X[req] = inface[s].recv[cnt]; cnt++; } } } } } } } } } //////////////////////////////////////////////////////////////////////////////////////// // 2.2 MPI: solve for upstream interface nodes # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Solve) starting with 2.2\n" ); # endif for( int i=neq_dn-1; i>=neq_up; i-- ) { for( int j=1; j<width[i]; j++ ) { int eq = index[i][j]; if( eq > i ) { X[i] -= ILU[i][j] * X[eq]; } } if( fabs(ILU[i][0]) < kZero ) REPORT::rpt.Error( kParameterFault, "division by zero - EQS::ILU_solver(1)" ); X[i] /= ILU[i][0]; } //////////////////////////////////////////////////////////////////////////////////////// // 2.3 MPI communication: // send to subdomains with smaller pid (2 -> 1) // s < pid ==> upstream interface nodes # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Solve) starting with 2.3\n" ); # endif if( project->subdom.npr > 1 ) { SUBDOM* subdom = &project->subdom; INFACE* inface = subdom->inface; int df = eqs->dfcn; for( int s=0; s<subdom->npr; s++ ) { int np = inface[s].np; // number of interface nodes if( np > 0 && s < subdom->pid ) // upstream interface nodes { int cnt = 0; for( int n=0; n<np; n++ ) { NODE* nd = inface[s].node[n]; if( !isFS(nd->flag, NODE::kDry) ) // nothing to send if node is dry... { SUB* sub = nd->sub; while( sub ) { if( sub->no == s ) break; sub = sub->next; } if( !sub->dry ) // ...or if the node is dry in { // any adjacent subdomain for( int e=0; e<df; e++ ) { int eqno = eqs->GetEqno( nd, e ); if( eqno >= 0 ) { inface[s].send[cnt] = X[eqno]; cnt++; } } } } } # ifdef _MPI_DBG { char text[200]; sprintf( text, " ### sending %d values to %d\n", cnt, s+1 ); REPORT::rpt.Output( text ); } # endif MPI_Send( &cnt, 1, MPI_INT, s, 1, MPI_COMM_WORLD ); if( cnt ) MPI_Send( inface[s].send, cnt, MPI_DOUBLE, s, 2, MPI_COMM_WORLD ); } } } # endif //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // 2.4 MPI: backward solve for interior nodes # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Solve) starting with 2.4\n" ); # endif for( int i=neq_up-1; i>=0; i-- ) { for( int j=1; j<width[i]; j++ ) { int eq = index[i][j]; if( eq > i ) { X[i] -= ILU[i][j] * X[eq]; } } if( fabs(ILU[i][0]) < kZero ) REPORT::rpt.Error( kParameterFault, "division by zero - EQS::ILU_solver(2)" ); X[i] /= ILU[i][0]; } # ifdef kDebug { FILE* dbg; char filename[80]; MODEL* model = project->M2D; GRID* region = model->region; if( project->subdom.npr == 1 ) sprintf( filename, "backX.dbg" ); else sprintf( filename, "backX_%02d.dbg", project->subdom.pid ); dbg = fopen( filename, "w" ); fprintf( dbg, "%d\n", region->Getnp() ); for( int n=0; n<region->Getnp(); n++ ) { NODE* nd = region->Getnode( n ); for( int e=0; e<eqs->dfcn; e++ ) { fprintf( dbg, "%5d %1d ", nd->Getname(), e ); int eqno = eqs->GetEqno( nd, e ); if( eqno >= 0 ) fprintf( dbg, "%14.6le\n", X[eqno] ); else fprintf( dbg, "%14.6le\n", 0.0 ); } } fclose( dbg ); } MPI_Barrier( MPI_COMM_WORLD ); # endif # ifdef _MPI_DBG REPORT::rpt.Output( " (PRECO_ILUT::Solve) backward solve finished\n" ); # endif }
void CRSMAT::AssembleEqs_im( EQS* eqs, double* vector, MODEL* model, PROJECT* project ) { int neq = eqs->neq; int dfcn = eqs->dfcn; int dfel = eqs->dfel; double* force = eqs->force; double** estifm = eqs->estifm; REPORT::rpt.Message( 3, "\n (CRSMAT::Assemble...) %s (%d elements)\n", "assembling eqs", model->ne ); // initializations --------------------------------------------------------------------- for( int i=0; i<neq; i++ ) vector[i] = 0.0; // ------------------------------------------------------------------------------------- // assemble elements for( int e=0; e<model->ne; e++ ) { ELEM* el = model->elem[e]; // compute element coefficients ------------------------------------------------------ if( !eqs->Coefs(el, project, estifm, force) ) continue; int nnd = el->Getnnd(); // insert element stiffness matrix (estifm) and (force) ------------------------------ for( int i=0; i<nnd; i++ ) // loop on nodes { for( int j=0; j<dfcn; j++ ) // loop on node-equations { int rind = i + j*nnd; int row = eqs->GetEqno( el->nd[i], j ); if( row >= 0 ) { REALPR* APtr = m_A[row]; double* estifmPtr = estifm[rind]; vector[row] += force[rind]; for( int k=0; k<nnd; k++ ) // loop on nodes { for( int l=0; l<dfcn; l++ ) // loop on node-equations { int cind = k + l*nnd; int col = eqs->GetEqno( el->nd[k], l ); if( col >= 0 ) { for( int m=0; m<m_width[row]; m++ ) { if( col == m_index[row][m] ) { APtr[m] += (REALPR) estifmPtr[cind]; break; } } } } } for( int l=0; l<dfel; l++ ) // loop on element-equations { int cind = dfcn*nnd + l; int col = eqs->GetEqno( el, l ); if( col >= 0 ) { for( int m=0; m<m_width[row]; m++ ) { if( col == m_index[row][m] ) { APtr[m] += (REALPR) estifmPtr[cind]; break; } } } } } } } for( int j=0; j<dfel; j++ ) // loop on element-equations { int rind = dfcn*nnd + j; int row = eqs->GetEqno( el, j ); if( row >= 0 ) { REALPR* APtr = m_A[row]; double* estifmPtr = estifm[rind]; vector[row] += force[rind]; for( int k=0; k<nnd; k++ ) // loop on nodes { for( int l=0; l<dfcn; l++ ) // loop on node-equations { int cind = k + l*nnd; int col = eqs->GetEqno( el->nd[k], l ); if( col >= 0 ) { for( int m=0; m<m_width[row]; m++ ) { if( col == m_index[row][m] ) { APtr[m] += (REALPR) estifmPtr[cind]; break; } } } } } for( int l=0; l<dfel; l++ ) // loop on element-equations { int cind = dfcn*nnd + l; int col = eqs->GetEqno( el, l ); if( col >= 0 ) { for( int m=0; m<m_width[row]; m++ ) { if( col == m_index[row][m] ) { APtr[m] += (REALPR) estifmPtr[cind]; break; } } } } } } } REPORT::rpt.Message( 3, "\n\n%-25s%s\n\n%15s %1s %8s %14s %14s\n\n", " (CRSMAT::Assemble...)", "Newton-Raphson-residuum / force vector ...", " ", " ", " node", " average", " maximum" ); for( int e=0; e<dfcn; e++ ) { int no = 0; double ave = 0.0; double max = 0.0; for( int n=0; n<model->np; n++ ) { NODE* nd = model->node[n]; int eqno = eqs->GetEqno( nd, e ); if( eqno >= 0 ) { double vec = vector[eqno]; ave += vec; if( fabs(vec) > fabs(max) ) { max = vec; no = nd->Getname(); } } } int tot = neq; ////////////////////////////////////////////////////////////////////////////////////// # ifdef _MPI_ max = project->subdom.Mpi_max( max ); tot = project->subdom.Mpi_sum( eqs->neq_up ); ave = project->subdom.Mpi_sum( ave ); # endif ////////////////////////////////////////////////////////////////////////////////////// if( tot ) ave /= tot; REPORT::rpt.Message( 3, " %15s %1d %8d %14.5le %14.5le\n", " ", e+1, no, ave, max ); } REPORT::rpt.Message( 3, "\n" ); }
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 GRID::ReportDry( PROJECT* project, double dryLimit, int countDown ) { int dryNodes = false; // check for dry nodes ------------------------------------------------------------------- for( int n=0; n<Getnp(); n++ ) { NODE* nd = Getnode(n); nd->countDown = 0; CF( nd->flag, NODE::kDry ); if( (nd->v.S - nd->z) < dryLimit ) { SF( nd->flag, NODE::kDry ); dryNodes = true; } } // report all dry nodes ------------------------------------------------------------------ if( dryNodes ) { REPORT::rpt.Output( "\n\n----------------------------------------", 5 ); REPORT::rpt.Output( "------------------------------\n", 5 ); REPORT::rpt.Output( "\n ... the following nodes are dry\n", 5 ); int jdry = 0; for( int n=0; n<Getnp(); n++ ) { NODE* nd = Getnode(n); if( isFS(nd->flag, NODE::kDry) ) { char text[20]; sprintf( text, " %5d", nd->Getname() ); REPORT::rpt.Output( text, 5 ); jdry++; if( !( jdry % 10) ) REPORT::rpt.Output( "\n", 5 ); } } if( jdry % 10 ) REPORT::rpt.Output( "\n", 5 ); // loop on all elements ---------------------------------------------------------------- for( int e=0; e<Getne(); e++ ) { ELEM* el = Getelem(e); CF( el->flag, ELEM::kDry ); int nnd = el->Getnnd(); for( int i=0; i<nnd; i++ ) { if( isFS(el->nd[i]->flag, NODE::kDry) ) { SF( el->flag, ELEM::kDry ); break; } } } for( int n=0; n<Getnp(); n++ ) { NODE* nd = Getnode(n); SF( nd->flag, NODE::kDry ); } // loop on all elements: all nodes at wet elements are wet ----------------------------- for( int e=0; e<Getne(); e++ ) { ELEM* el = Getelem(e); if( !isFS(el->flag, ELEM::kDry) ) { int nnd = el->Getnnd(); for( int i=0; i<nnd; i++ ) CF( el->nd[i]->flag, NODE::kDry ); } } int idry = 0; REPORT::rpt.Output( "\n ... the following elements are dry\n", 5 ); for( int e=0; e<Getne(); e++ ) { ELEM* el = Getelem(e); if( isFS(el->flag, ELEM::kDry) ) { char text[20]; sprintf( text, " %5d", el->Getname() ); REPORT::rpt.Output( text, 5 ); idry++; if( !( idry % 10) ) REPORT::rpt.Output( "\n", 5 ); } } if( idry % 10 ) REPORT::rpt.Output( "\n", 5 ); REPORT::rpt.Output( "\n", 5 ); for( int n=0; n<Getnp(); n++ ) { NODE* nd = Getnode(n); if( isFS(nd->flag, NODE::kDry) ) { nd->v.U = 0.0; nd->v.V = 0.0; nd->v.S = nd->z; nd->v.K = 0.0; nd->v.D = 0.0; nd->v.dUdt = 0.0; nd->v.dVdt = 0.0; nd->v.dSdt = 0.0; } } } }
int GRID::Dry( double dryLimit, int countDown ) { // initialization: mark all dry nodes and elements ------------------------------------- for( int n=0; n<Getnp(); n++ ) { NODE* nd = Getnode(n); if( isFS(nd->flag, NODE::kDry) ) nd->mark = true; else nd->mark = false; SF( nd->flag, NODE::kDry ); } for( int e=0; e<Getne(); e++ ) { ELEM* el = Getelem(e); if ( isFS(el->flag, ELEM::kDry) ) el->mark = true; else el->mark = false; CF( el->flag, ELEM::kDry ); } // loop on all elements ---------------------------------------------------------------- for( int e=0; e<Getne(); e++ ) { ELEM* el = Getelem(e); int ncn = el->Getncn(); for( int i=0; i<ncn; i++ ) { // set element dry, if flow depth is less than dry limit --------------------------- // or the node was already dry double H = el->nd[i]->v.S - el->nd[i]->z; if( H < dryLimit || el->nd[i]->mark ) { SF( el->flag, ELEM::kDry ); } } } // loop on all elements: all nodes at wet elements are wet ----------------------------- for( int e=0; e<Getne(); e++ ) { ELEM* el = Getelem(e); if( !isFS(el->flag, ELEM::kDry) ) { int nnd = el->Getnnd(); for( int i=0; i<nnd; i++ ) CF( el->nd[i]->flag, NODE::kDry ); } } // report all nodes that have got newly dry -------------------------------------------- REPORT::rpt.Output( "\n (dry) the following nodes have got dry\n", 5 ); int jdry = 0; for( int n=0; n<Getnp(); n++ ) { NODE* nd = Getnode(n); if( isFS(nd->flag, NODE::kDry) ) { nd->v.U = 0.0; nd->v.V = 0.0; nd->v.S = nd->z; nd->v.K = 0.0; nd->v.D = 0.0; nd->v.dUdt = 0.0; nd->v.dVdt = 0.0; nd->v.dSdt = 0.0; if( !nd->mark ) { nd->countDown = countDown; char text[20]; sprintf( text, " %5d", nd->Getname() ); REPORT::rpt.Output( text, 2 ); jdry++; if( !( jdry % 10) ) REPORT::rpt.Output( "\n", 5 ); } } nd->mark = false; } if( jdry % 10 ) REPORT::rpt.Output( "\n", 5 ); // report all elements that have got newly dry ------------------------------------------- REPORT::rpt.Output( "\n (dry) the following elements have got dry\n", 5 ); int idry = 0; for( int e=0; e<Getne(); e++ ) { ELEM* el = Getelem( e ); if( isFS(el->flag, ELEM::kDry) && !el->mark ) { char text[20]; sprintf( text, " %5d", el->Getname() ); REPORT::rpt.Output( text, 5 ); idry++; if( !( idry % 10) ) REPORT::rpt.Output( "\n", 5 ); } el->mark = false; } if( idry % 10 ) REPORT::rpt.Output( "\n", 5 ); return idry + jdry; }
int GRID::Rewet( double rewetLimit, int rewetPasses, PROJECT* project ) { int i, j, k; int l, m, pass, ncn, nnd, rewetFlag; double wElev, K, D, cm, cd, vt; char text[80]; cm = project->KD.cm; cd = project->KD.cd; // initialization: mark all dry elements ----------------------------------------------- for( int e=0; e<Getne(); e++ ) { ELEM* el = Getelem(e); el->mark = false; if( isFS(el->flag, ELEM::kDry) ) { el->mark = true; } } REPORT::rpt.Output( "\n (rewet) the following nodes have been rewetted\n", 5 ); m = 0; for( pass=0; pass<rewetPasses; pass++ ) { for( int n=0; n<Getnp(); n++ ) { NODE* nd = Getnode(n); nd->mark = false; } sprintf( text, " pass %d ...\n", pass+1 ); REPORT::rpt.Output( text, 5 ); for( int e=0; e<Getne(); e++ ) { ELEM * el = Getelem(e); if( isFS(el->flag, ELEM::kBound) ) continue; TYPE* type = TYPE::Getid( el->type ); // look only for dry elements ------------------------------------------------------ if( isFS(el->flag, ELEM::kDry) ) { // loop on corner nodes: minimal water elevation --------------------------------- ncn = el->Getncn(); // number of corner nodes nnd = el->Getnnd(); // total number of nodes rewetFlag = false; wElev = 0.0; for( j=0, i=0; j<ncn; j++ ) { if( !isFS(el->nd[j]->flag, NODE::kDry) ) { // determine averaged water elevation at wet points -------------------------- rewetFlag = true; wElev += el->nd[j]->v.S; i++; } } // loop on all nodes: check for rewetting ---------------------------------------- if( i ) { wElev /= i; for( j=0; j<nnd; j++ ) { if( (wElev - el->nd[j]->z) < rewetLimit ) rewetFlag = false; } } // if all nodes have been rewetted, rewet whole element -------------------------- if( rewetFlag ) { for( j=0; j<ncn; j++ ) { // re-initialize flow parameters --------------------------------------------- if( isFS(el->nd[j]->flag, NODE::kDry) ) { el->nd[j]->mark = true; el->nd[j]->v.S = wElev; } } for( j=ncn; j<nnd; j++ ) { if( isFS(el->nd[j]->flag, NODE::kDry) ) { el->nd[j]->mark = true; // get left and right corner node to midside node j ------------------------ el->GetLShape()->getCornerNodes( j, &i, &k ); el->nd[j]->v.S = (el->nd[i]->v.S + el->nd[k]->v.S) / 2.0; } } for( j=0; j<nnd; j++ ) { if( isFS(el->nd[j]->flag, NODE::kDry) ) { el->nd[j]->v.U = 0.0; el->nd[j]->v.V = 0.0; el->nd[j]->v.dUdt = 0.0; el->nd[j]->v.dVdt = 0.0; el->nd[j]->v.dSdt = 0.0; K = el->nd[j]->v.K = dryRew.interpolate(el->nd[j], kVarK, 1); D = el->nd[j]->v.D = dryRew.interpolate(el->nd[j], kVarD, 1); if( isFS(project->actualTurb, BCONSET::kVtConstant) ) { el->nd[j]->vt = type->vt; } else if( isFS(project->actualTurb, BCONSET::kVtPrandtlKol) ) { if( fabs(D) > 0.0 ) vt = cm * cd * K * K / D; else vt = 0.0; el->nd[j]->vt = vt; } } } } } } // check count down for nodes to be rewetted and report ------------------------------ l = 0; for( int n=0; n<Getnp(); n++ ) { NODE* nd = Getnode(n); if( nd->mark ) { nd->countDown--; if( nd->countDown <= 0 ) { CF( nd->flag, NODE::kDry ); // look for boundary conditions ------------------------------------------------ BCON *bc = &nd->bc; // ... outflow boundary or fixed flow depth h -------------------------------- if( isFS(bc->kind, BCON::kOutlet) || isFS(bc->kind, BCON::kSetS) ) { nd->v.S = bc->val->S; } // ... inflow boundary or fixed velocities U,V ------------------------------- if( isFS(bc->kind, BCON::kInlet) ) { nd->v.U = bc->val->U * bc->niox / (nd->v.S - nd->z); nd->v.V = bc->val->U * bc->nioy / (nd->v.S - nd->z); } else if( !isFS(bc->kind, BCON::kAutoSlip) ) { if ( isFS(bc->kind, BCON::kFixU) ) nd->v.U = bc->val->U; if ( isFS(bc->kind, BCON::kFixV) ) nd->v.V = bc->val->V; } # ifdef kDebug sprintf( text, " %5d (UVhKDvt): %9.2le %9.2le %9.2le %9.2le %9.2le %9.2le\n", nd->Getname(), nd->v.U, nd->v.V, nd->v.S - nd->z, nd->v.K, nd->v.D, nd->vt ); REPORT::rpt.Output( text, 5 ); # else sprintf( text, " %5d", nd->Getname() ); REPORT::rpt.Output( text, 5 ); l++; if( !( l % 10) ) REPORT::rpt.Output( "\n", 5 ); # endif m++; } else { nd->v.U = 0.0; nd->v.V = 0.0; nd->v.K = 0.0; nd->v.D = 0.0; nd->v.S = nd->z; } } nd->mark = false; } # ifndef kDebug if( l % 10 ) REPORT::rpt.Output( "\n", 5 ); # endif // rewet all dry elements without dry nodes ------------------------------------------ for( int e=0; e<Getne(); e++ ) { ELEM* el = Getelem(e); if( isFS(el->flag, ELEM::kDry) ) { nnd = el->Getnnd(); rewetFlag = true; for( j=0; j<nnd; j++ ) { if( isFS(el->nd[j]->flag, NODE::kDry) ) { rewetFlag = false; break; } } if( rewetFlag ) { CF( el->flag, ELEM::kDry ); } } } } // loop on all elements: all nodes at wet elements are wet ----------------------------- for( int n=0; n<Getnp(); n++ ) { NODE* nd = Getnode(n); SF( nd->flag, NODE::kDry ); nd->mark = false; } for( int e=0; e<Getne(); e++ ) { ELEM* el = Getelem(e); if( !isFS(el->flag, ELEM::kDry) ) { nnd = el->Getnnd(); for( j=0; j<nnd; j++ ) CF( el->nd[j]->flag, NODE::kDry ); } } for( int n=0; n<Getnp(); n++ ) { NODE* nd = Getnode(n); if( isFS(nd->flag, NODE::kDry) ) { nd->v.U = 0.0; nd->v.V = 0.0; nd->v.K = 0.0; nd->v.D = 0.0; nd->v.S = nd->z; } } // report elements which have been rewetted -------------------------------------------- REPORT::rpt.Output( "\n (rewet) the following elements have been rewetted\n", 5 ); l = 0; for( int e=0; e<Getne(); e++ ) { ELEM* el = Getelem(e); nnd = el->Getnnd(); if( el->mark && !isFS(el->flag, ELEM::kDry) ) { for( j=0; j<nnd; j++ ) { if( isFS(el->nd[j]->flag, NODE::kDry) ) REPORT::rpt.Error ("unexpected error - rewet (1)"); } sprintf( text, " %5d", el->Getname() ); REPORT::rpt.Output( text, 5 ); l++; if( !( l % 10) ) REPORT::rpt.Output( "\n", 5 ); } el->mark = false; } if( l % 10 ) REPORT::rpt.Output( "\n", 5 ); # ifndef kDebug if( l % 10 ) REPORT::rpt.Output( "\n", 5 ); # endif return l; }
void EQS::Update( MODEL* model, SUBDOM* subdom, double* X, int ind, int varInd, double* maxAbs, double* maxPer, double* avAbs, double* avPer, int* noAbs, int* noPer ) { *maxAbs = 0.0; *maxPer = 0.0; *avAbs = 0.0; *avPer = 0.0; *noAbs = -1; *noPer = -1; int countAbs = 0; int countPer = 0; for( int n=0; n<model->np; n++ ) { NODE* nd = model->node[n]; int eqno = GetEqno( nd, ind ); if( eqno >= 0 ) { double chAbs = fabs( X[eqno] ); // absolute changes, maximum and on average *avAbs += chAbs; countAbs++; if( chAbs > *maxAbs ) { *maxAbs = chAbs; *noAbs = nd->Getname(); } // percentage changes, maximum and on average double H = nd->v.S - nd->z; double val = 0.0; switch( varInd ) { case kVarU: val = nd->v.U; break; case kVarV: val = nd->v.V; break; case kVarH: case kVarS: val = H; break; case kVarK: val = nd->v.K; break; case kVarD: val = nd->v.D; break; case kVarC: val = nd->v.C; break; case kVarQb: val = nd->v.Qb; break; case kVarDz: val = nd->dz; break; case kVarUH: val = H * nd->v.U; break; case kVarVH: val = H * nd->v.V; break; } if( fabs(val) > 1.0e-9 ) { double chPer = chAbs / fabs(val); *avPer += fabs(chPer); countPer++; if( fabs(chPer) > fabs(*maxPer) ) { *maxPer = chPer; *noPer = nd->Getname(); } } } } //////////////////////////////////////////////////////////////////////////////////////// # ifdef _MPI_ int mpi_noAbs; int mpi_noPer; double mpi_maxAbs; double mpi_maxPer; if( subdom->pid == 0 ) { MPI_Status status; for( int s=1; s<subdom->npr; s++ ) { MPI_Recv( &mpi_noAbs, 1, MPI_INT, s, 1, MPI_COMM_WORLD, &status ); MPI_Recv( &mpi_maxAbs, 1, MPI_DOUBLE, s, 2, MPI_COMM_WORLD, &status ); if( mpi_maxAbs > *maxAbs ) { *noAbs = mpi_noAbs; *maxAbs = mpi_maxAbs; } MPI_Recv( &mpi_noPer, 1, MPI_INT, s, 1, MPI_COMM_WORLD, &status ); MPI_Recv( &mpi_maxPer, 1, MPI_DOUBLE, s, 2, MPI_COMM_WORLD, &status ); if( fabs(mpi_maxPer) > fabs(*maxPer) ) { *noPer = mpi_noPer; *maxPer = mpi_maxPer; } } } else { MPI_Send( noAbs, 1, MPI_INT, 0, 1, MPI_COMM_WORLD ); MPI_Send( maxAbs, 1, MPI_DOUBLE, 0, 2, MPI_COMM_WORLD ); MPI_Send( noPer, 1, MPI_INT, 0, 1, MPI_COMM_WORLD ); MPI_Send( maxPer, 1, MPI_DOUBLE, 0, 2, MPI_COMM_WORLD ); } MPI_Bcast( noAbs, 1, MPI_INT, 0, MPI_COMM_WORLD ); MPI_Bcast( maxAbs, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD ); MPI_Bcast( noPer, 1, MPI_INT, 0, MPI_COMM_WORLD ); MPI_Bcast( maxPer, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD ); //*maxAbs = subdom->Mpi_max( *maxAbs ); countAbs = subdom->Mpi_sum( countAbs ); *avAbs = subdom->Mpi_sum( *avAbs ); # endif //////////////////////////////////////////////////////////////////////////////////////// *avAbs /= countAbs; if( countPer ) *avPer /= countPer; *avPer *= 100.0; *maxPer *= 100.0; }
void MODEL::Boundary() { char text[200]; // initializations --------------------------------------------------------------------- if( !boundList ) { boundList = new ELEM* [region->Getnp()]; if( !boundList ) REPORT::rpt.Error( kMemoryFault, "can not allocate memory - MODEL::Boundary(1)" ); } for( int n=0; n<region->Getnp(); n++ ) { NODE* nd = region->Getnode(n); CF( nd->flag, NODE::kBound ); nd->mark = false; // remove slip boundary conditions --------------------------------------------------- if( isFS(nd->bc.kind, BCON::kAutoSlip) ) { CF( nd->bc.kind, BCON::kAutoSlip | BCON::kFixU | BCON::kFixV ); } if( isFS(nd->bc.kind, BCON::kAutoKD) ) { CF( nd->bc.kind, BCON::kAutoKD | BCON::kFixK | BCON::kFixD ); } } // determine boundary midside nodes ---------------------------------------------------- for( int n=0; n<region->Getnp(); n++ ) { NODE* nd = region->Getnode(n); // midside nodes which are connected to only one element are boundary nodes ---------- if( nd->noel == 1 && isFS(nd->flag, NODE::kMidsNode) ) { if( !isFS(nd->flag, NODE::kInface) ) SF( nd->flag, NODE::kBound ); } } // determine number of boundary elements: nb ------------------------------------------- int nb = 0; for( int n=0; n<region->Getnp(); n++ ) { if( isFS(region->Getnode(n)->flag,NODE::kBound) ) nb++; } // allocate memory for boundary elements ----------------------------------------------- bound->Free(); bound->Alloc( 0, nb ); // set up boundary elements ------------------------------------------------------------ int be = 0; // counter for boundary elements for( int re=0; re<region->Getne(); re++ ) { ELEM* el = region->Getelem(re); if( isFS(el->flag, ELEM::kDry) ) continue; int ncn = el->Getncn(); int nnd = el->Getnnd(); for( int i=ncn; i<nnd; i++ ) { // check, if el->nd[i] is a midside boundary node ---------------------------------- if( isFS(el->nd[i]->flag, NODE::kBound) ) { ELEM* bd = bound->Getelem(be); boundList[el->nd[i]->Getno()] = bd; int left = i - ncn; int rght = (left + 1) % ncn; bd->nd[0] = el->nd[left]; // corner nodes bd->nd[1] = el->nd[rght]; bd->nd[2] = el->nd[i]; // midside node SF( bd->nd[0]->flag, NODE::kBound ); SF( bd->nd[1]->flag, NODE::kBound ); // set shape specifications ------------------------------------------------------ bd->Setshape( kLine ); bd->Setname( el->Getname() ); SF( bd->flag, ELEM::kBound ); bd->type = el->type; bd->areaFact = 1.0; be++; } } } //////////////////////////////////////////////////////////////////////////////////////// // communicate boundary nodes //# ifdef _MPI_DBG // REPORT::rpt.Output( " (MODEL::Boundary) communication of boundary nodes", 1 ); //# endif # ifdef _MPI_ if( subdom->npr > 1 ) { INFACE* inface = subdom->inface; // loop on all interfaces: exchange bound flag --------------------------------------- for( int s=0; s<subdom->npr; s++ ) { MPI_Status status; int npinf = inface[s].np; if( npinf > 0 ) { for( int n=0; n<npinf; n++ ) { NODE* nd = inface[s].node[n]; if( isFS(nd->flag, NODE::kBound) ) inface[s].sia1[n] = true; else inface[s].sia1[n] = false; } MPI_Sendrecv( inface[s].sia1, npinf, MPI_CHAR, s, 1, inface[s].ria1, npinf, MPI_CHAR, s, 1, MPI_COMM_WORLD, &status ); for( int n=0; n<npinf; n++ ) { NODE* nd = inface[s].node[n]; if( inface[s].ria1[n] ) SF( nd->flag, NODE::kBound ); } } } } # endif //////////////////////////////////////////////////////////////////////////////////////// // ------------------------------------------------------------------------------------- // count for newly required boundary conditions // note: (sc, 30.10.2004) // a boundary condition is needed for marsh-nodes in case of dry-rewet-method 3 int nbc = 0; for( int n=0; n<region->Getnp(); n++ ) { NODE* nd = region->Getnode(n); if( isFS(nd->flag, NODE::kBound) ) nbc++; } sprintf( text,"\n (MODEL::Boundary) number of boundary elements: %d\n", nb ); REPORT::rpt.Output( text, 3 ); # ifdef kDebug { int pid; MPI_Comm_rank( MPI_COMM_WORLD, &pid ); char fname[40]; sprintf( fname, "bound_%02d.inp", pid+1 ); FILE* id = fopen( fname, "w" ); for( int n=0; n<region->Getnp(); n++ ) { NODE* nd = region->Getnode(n); CF( nd->flag, NODE::kMarker ); } for( int e=0; e<bound->Getne(); e++ ) { ELEM* el = bound->Getelem(e); for( int i=0; i<el->getnnd(); i++ ) { SF( el->nd[i]->flag, NODE::kMarker ); } } int j = 0; for( int n=0; n<region->Getnp(); n++ ) { NODE* nd = region->Getnode(n); if( isFS(nd->flag, NODE::kMarker) ) j++; } fprintf( id, "%6d %6d 0 0 0\n", j, nb ); for( int n=0; n<region->Getnp(); n++ ) { NODE* nd = region->Getnode(n); if( isFS(nd->flag, NODE::kMarker) ) { fprintf( id, "%6d %17.9le %17.9le %17.9le\n", nd->Getname(), nd->x, nd->y, nd->z ); } } for( int e=0; e<bound->Getne(); e++ ) { ELEM* el = bound->Getelem(e); fprintf( id, "%6d %3d line %6d %6d %6d\n", el->Getname(), TYPE::getid(el->type), el->nd[0]->Getname(), el->nd[1]->Getname(), el->nd[2]->Getname() ); } fclose( id ); } # endif }