/*
    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 failure( void )
{
  long int element=0, max_element=0, delete_elem=0, length=0, 
    inol=0, nnol=0, inod=0, idim=0, jdim=0, swit=0, swit_element=0, 
    element_group=0, max_dependency_item=0, any_failure=0, max=0, idep=0, 
    ldum=0, el[MNOL+1], nodes[MNOL], *dependency_item=NULL;
  double failure=0., strain_size=0., damage_size=0.,
    ddum[1], average_node_dof[MUKNWN], *node_dof=NULL;

  if ( materi_strain_plasti || materi_strain_total || materi_damage ) {
    
    if ( db_max_index( GROUP_MATERI_STRAIN_PLASTI_FAILURE, max, VERSION_NORMAL, GET ) >=0 || 
         db_max_index( GROUP_MATERI_STRAIN_TOTAL_FAILURE, max, VERSION_NORMAL, GET ) >=0 ||
         db_max_index( GROUP_MATERI_DAMAGE_FAILURE, max, VERSION_NORMAL, GET ) >=0 ) 
      any_failure = 1;
    db_max_index( DEPENDENCY_ITEM, max_dependency_item, VERSION_NORMAL, GET );
    for ( idep=0; idep<=max_dependency_item; idep++ ) {
      if ( db_active_index( DEPENDENCY_ITEM, idep, VERSION_NORMAL ) ) {
        dependency_item = db_int( DEPENDENCY_ITEM, idep, VERSION_NORMAL );
        if ( scalar_iabs(dependency_item[0])==GROUP_MATERI_STRAIN_PLASTI_FAILURE ||
             scalar_iabs(dependency_item[0])==GROUP_MATERI_STRAIN_TOTAL_FAILURE ||
             scalar_iabs(dependency_item[0])==GROUP_MATERI_DAMAGE_FAILURE ) 
          any_failure = 1;
      }
    }

    if ( any_failure ) {
      swit = set_swit(-1,-1,"failure");
      if ( swit ) pri( "In routine FAILURE" );

        // loop over elements
      db_max_index( ELEMENT, max_element, VERSION_NORMAL, GET );
      for ( element=0; element<=max_element; element++ ) {
        if ( db_active_index( ELEMENT, element, VERSION_NORMAL ) ) {
          swit_element = swit; swit = swit && set_swit(element,-1,"");
          db( ELEMENT, element, el, ddum, length, VERSION_NORMAL, GET );
          nnol = length - 1; array_move( &el[1], nodes, nnol );
          array_set( average_node_dof, 0., nuknwn );
          for ( inol=0; inol<nnol; inol++ ) {
            inod = nodes[inol];
            node_dof = db_dbl( NODE_DOF, inod, VERSION_NORMAL );
            array_add( average_node_dof, node_dof, average_node_dof, nuknwn );
          }
          array_multiply( average_node_dof, average_node_dof, 1./((double)nnol), nuknwn );
          if ( db_active_index( ELEMENT_GROUP, element, VERSION_NORMAL ) )
            db( ELEMENT_GROUP, element, &element_group, ddum, ldum, VERSION_NORMAL, GET );
          else
            element_group = 0;
          delete_elem = 0;
          if ( get_group_data( GROUP_MATERI_STRAIN_PLASTI_FAILURE, element_group, 
            average_node_dof, &failure, ldum, GET_IF_EXISTS ) ) {
            strain_size = 0.;
            for ( idim=0; idim<MDIM; idim++ ) {
              for ( jdim=0; jdim<MDIM; jdim++ ) {
                strain_size += scalar_square( average_node_dof[epp_indx+
                  stress_indx(idim,jdim)*nder] );
              }
            }
            strain_size = sqrt( 0.5*strain_size );
            if ( strain_size>failure ) {
              delete_elem = 1;
              if ( swit ) {
                pri( "element", element );
                pri( "average_node_dof", average_node_dof, nuknwn );
                pri( "strain_size", strain_size );
                pri( "delete_elem", delete_elem );
              }
            }
          }
          if ( get_group_data( GROUP_MATERI_STRAIN_TOTAL_FAILURE, element_group, 
            average_node_dof, &failure, ldum, GET_IF_EXISTS ) ) {
            strain_size = 0.;
            for ( idim=0; idim<MDIM; idim++ ) {
              for ( jdim=0; jdim<MDIM; jdim++ ) {
                strain_size += scalar_square( average_node_dof[ept_indx+
                  stress_indx(idim,jdim)*nder] );
              }
            }
            strain_size = sqrt( 0.5*strain_size );
            if ( strain_size>failure ) {
              delete_elem = 1;
              if ( swit ) {
                pri( "element", element );
                pri( "average_node_dof", average_node_dof, nuknwn );
                pri( "strain_size", strain_size );
                pri( "delete_elem", delete_elem );
              }
            }
          }
          if ( get_group_data( GROUP_MATERI_DAMAGE_FAILURE, element_group, 
            average_node_dof, &failure, ldum, GET_IF_EXISTS ) ) {
            damage_size = scalar_dabs( average_node_dof[dam_indx] );
            if ( damage_size>failure ) {
              delete_elem = 1;
              if ( swit ) {
                pri( "element", element );
                pri( "average_node_dof", average_node_dof, nuknwn );
                pri( "damage_size", damage_size );
                pri( "delete_elem", delete_elem );
              }
            }
          }
          if ( delete_elem ) delete_element( element, VERSION_NORMAL );
          swit = swit_element;
        }
      }
      mesh_has_changed( VERSION_NORMAL );

      if ( swit ) pri( "Out routine FAILURE" );
    }

  }

}
