Пример #1
0
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;
        }
      }
    }
  }
}
Пример #2
0
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;
}
Пример #3
0
void MODEL::MPI_Comm_Dry( PROJECT* project, int initialize )
{
# ifdef _MPI_

  DRYREW* dryRew = &region->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_
}
Пример #4
0
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;
    }
  }
}
Пример #5
0
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;
}
Пример #6
0
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);
}