/*
    Copyright (C) 1998  Dennis Roddeman
    email: dennis.roddeman@uibk.ac.at

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software Foundation 
    59 Temple Place, Suite 330, Boston, MA, 02111-1307, USA
*/

#include "tochnog.h"

void tyings_setup( long int from_node, long int to_node, 
  long int tyings_unknowns[] )

  /* Conditions:
     - each node can only be tyed to one other element
     - the nodes of the other element cannot be tyed themselves
  */

{
  long int in=0, inol=0, inod=0, element=0, max_element=0, nnol=0, 
    length=0, swit=0, name=0, found=0, other_element_tyed=0,
    ldum=0, idum[1], nodes[MNOL], el[MNOL+1];
  double ddum[1], coord[MDIM], coords[MNOL*MDIM], weight[MNOL];

  swit = set_swit(-1,-1,"tyings_setup");
  if ( swit ) cout << "In routine TYINGS_SETUP\n";

  if ( nuknwn>0 ) {
    db_max_index( ELEMENT, max_element, VERSION_NORMAL, GET );
    for ( inod=from_node; inod<=to_node; inod++ ) {
      if ( db_active_index( NODE, inod, VERSION_NORMAL ) ) { 
        if ( swit ) pri( "generating tyings for inod", inod );
        found = 0; db( NODE, inod, idum, coord, ldum, VERSION_NORMAL, GET );
        for ( element=0; element<=max_element && !found; element++ ) {
          if ( db_active_index( ELEMENT, element, VERSION_NORMAL ) ) {
            if ( swit ) pri( "element", element );
            db( ELEMENT, element, el, ddum, length, VERSION_NORMAL, GET );
            name = el[0]; nnol = length-1; array_move( &el[1], nodes, nnol );
            if ( !array_member(nodes,inod,nnol,ldum) ) {
              for ( inol=0; inol<nnol; inol++ ) {
                in = nodes[inol];
                db( NODE, in, idum, &coords[inol*ndim], 
                  ldum, VERSION_NORMAL, GET );
              }
              if ( point_el( coord, coords, weight, name, nnol ) ) {
                other_element_tyed = 0;
                for ( inol=0; inol<nnol; inol++ ) {
                  in = nodes[inol];
                  if ( db_active_index( NODE_TYINGS, in, VERSION_NORMAL ) ) 
                    other_element_tyed = 1;
                }
                if ( !other_element_tyed ) {               
                  found = 1;
                  if ( swit ) {
                    pri( "node_tyings", nodes, nnol );
                    pri( "node_tyings_factors", weight, nnol );
                  }
                  db( NODE_TYINGS, inod, nodes, ddum, nnol, 
                    VERSION_NORMAL, PUT );
                  db( NODE_TYINGS_FACTORS, inod, idum, weight, nnol, 
                    VERSION_NORMAL, PUT );
                  db( NODE_TYINGS_UNKNOWNS, inod, tyings_unknowns, 
                    ddum, nuknwn, VERSION_NORMAL, PUT );
                }
              }
            }
          }
        }
      }
    }

  }

  if ( swit ) cout << "Out routine TYINGS_SETUP\n";

}

void tyings_rhside_lhside( void )

{
  long int in=0, inod=0, max_node=0, ipuknwn=0, max=0, 
    length=0, *node_tyings=NULL, *node_tyings_unknowns=NULL;
  double *node_tyings_factors=NULL, *node_rhside=NULL, *node_lhside=NULL,
    *node_rhside_tyings=NULL, *node_lhside_tyings=NULL;

  if ( db_max_index( NODE_TYINGS, max, VERSION_NORMAL, GET ) >= 0 ) {
    db_max_index( NODE, max_node, VERSION_NORMAL, GET );
    for ( inod=0; inod<=max_node; inod++ ) {
      if ( db_active_index( NODE_TYINGS, inod, VERSION_NORMAL ) ) { 
        node_rhside = db_dbl( NODE_RHSIDE, inod, VERSION_NORMAL );
        node_lhside = db_dbl( NODE_LHSIDE, inod, VERSION_NORMAL );
        node_tyings = db_int( NODE_TYINGS, inod, VERSION_NORMAL );
        node_tyings_factors = db_dbl( NODE_TYINGS_FACTORS, inod, VERSION_NORMAL );
        node_tyings_unknowns = db_int( NODE_TYINGS_UNKNOWNS, inod, VERSION_NORMAL );
        length = db_len( NODE_TYINGS, inod, VERSION_NORMAL );
        for ( in=0; in<length; in++ ) {
          node_rhside_tyings = db_dbl( NODE_RHSIDE, 
            node_tyings[in], VERSION_NORMAL );
          node_lhside_tyings = db_dbl( NODE_LHSIDE, 
            node_tyings[in], VERSION_NORMAL );
          for ( ipuknwn=0; ipuknwn<npuknwn; ipuknwn++ ) {
            if ( node_tyings_unknowns[ipuknwn]==-YES ) {
              node_rhside_tyings[ipuknwn] += 
                node_tyings_factors[in] * node_rhside[ipuknwn];
              node_lhside_tyings[ipuknwn] += 
                node_tyings_factors[in] * node_lhside[ipuknwn];
            }
          }
        }
      }
    }
  }

}

void tyings_node_dof( long int version )

{
  long int in=0, inod=0, ider=0, ipuknwn=0, max_node=0, iuknwn=0, max=0, length=0, 
    *node_tyings=NULL, *node_tyings_unknowns=NULL;
  double *node_tyings_factors=NULL, *node_dof=NULL, *node_dof_tyings=NULL;

  if ( db_max_index( NODE_TYINGS, max, VERSION_NORMAL, GET ) >= 0 ) {
    db_max_index( NODE, max_node, VERSION_NORMAL, GET );
    for ( inod=0; inod<=max_node; inod++ ) {
      if ( db_active_index( NODE_TYINGS, inod, VERSION_NORMAL ) ) { 
        node_dof = db_dbl( NODE_DOF, inod, version );
        array_set( node_dof, 0., nuknwn );
        node_tyings = db_int( NODE_TYINGS, inod, VERSION_NORMAL );
        node_tyings_factors = db_dbl( NODE_TYINGS_FACTORS, inod, VERSION_NORMAL );
        node_tyings_unknowns = db_int( NODE_TYINGS_UNKNOWNS, inod, VERSION_NORMAL );
        length = db_len( NODE_TYINGS, inod, VERSION_NORMAL );
        for ( in=0; in<length; in++ ) {
          node_dof_tyings = db_dbl( NODE_DOF, node_tyings[in], version );
          for ( ipuknwn=0; ipuknwn<npuknwn; ipuknwn++ ) {
            if ( node_tyings_unknowns[ipuknwn]==-YES ) {
              for ( ider=0; ider<nder; ider++ ) {
                iuknwn = ipuknwn*nder + ider;
                node_dof[iuknwn] += node_tyings_factors[in] * 
                  node_dof_tyings[iuknwn];
              }
            }
          }
        }
      }
    }
  }

}
