/*
    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"

#define DELTA 1.e-1


void hyperelasticity( long int element, long int gr, double old_unknowns[],
  double new_unknowns[], double old_epe[], double new_epe[], double new_sig[] )

{
  long int hyper_type=NONE, iloop=0, idim=0, jdim=0, indx=0, swit=0, ldum=0;
  double variation=0., W_right=0., W_left=0.,
    old_hyper_besseling[3], new_hyper_besseling[3], 
    old_hyper_mooney_rivlin[2], new_hyper_mooney_rivlin[2], 
    work[MDIM*MDIM], C[MDIM*MDIM], tmp_stress[MDIM*MDIM], 
    old_stress[MDIM*MDIM], new_stress[MDIM*MDIM], *epe=NULL, *hyper_data=NULL;

  if ( get_group_data( GROUP_MATERI_HYPER_BESSELING, gr, new_unknowns,
      new_hyper_besseling, ldum, GET_IF_EXISTS ) ) {
    hyper_type = GROUP_MATERI_HYPER_BESSELING;
    get_group_data( GROUP_MATERI_HYPER_BESSELING, gr, old_unknowns, 
      old_hyper_besseling, ldum, GET );
  }
  else if ( get_group_data( GROUP_MATERI_HYPER_MOONEY_RIVLIN, gr, new_unknowns,
      new_hyper_mooney_rivlin, ldum, GET_IF_EXISTS ) ) {
    hyper_type = GROUP_MATERI_HYPER_MOONEY_RIVLIN;
    get_group_data( GROUP_MATERI_HYPER_MOONEY_RIVLIN, gr, old_unknowns, 
      old_hyper_mooney_rivlin, ldum, GET );
  }

  if ( hyper_type!=NONE ) {

    swit = set_swit(element,-1,"hyperelasticity");
    if ( swit ) pri( "In HYPERELASTICITY" );

      /* Determine old stress and new stress, because we need to
         get the incremental stress and the old hyperelastic stress
         is not stored */
    for ( iloop=0; iloop<=1; iloop++ ) {
      if ( iloop==0 ) {
        epe = old_epe;
        if ( hyper_type==GROUP_MATERI_HYPER_BESSELING )
          hyper_data = old_hyper_besseling;
        else {
          assert( hyper_type==GROUP_MATERI_HYPER_MOONEY_RIVLIN );
          hyper_data = old_hyper_mooney_rivlin;
        }
      }
      else {
        epe = new_epe;
        if ( hyper_type==GROUP_MATERI_HYPER_BESSELING )
          hyper_data = new_hyper_besseling;
        else {
          assert( hyper_type==GROUP_MATERI_HYPER_MOONEY_RIVLIN );
          hyper_data = new_hyper_mooney_rivlin;
        }
      }
        // central differences to determine stresses
      variation = DELTA * array_size( epe, MDIM*MDIM );
      if ( variation==0. ) variation = 1.e-2;
      array_move( epe, work, MDIM*MDIM );
      for ( idim=0; idim<MDIM; idim++ ) work[idim*MDIM+idim] += 1.;
      matrix_atb( work, work, C, MDIM, MDIM, MDIM );
      for ( idim=0; idim<MDIM; idim++ ) {
        for ( jdim=idim; jdim<MDIM; jdim++ ) {
          indx = idim*MDIM + jdim;
          C[indx] += variation;
          hyper_law( hyper_type, hyper_data, C, W_right );
          C[indx] -= 2. * variation;
          hyper_law( hyper_type, hyper_data, C, W_left );
          tmp_stress[idim*MDIM+jdim] = tmp_stress[jdim*MDIM+idim] = 
            2.*(W_right-W_left)/(2.*variation);
          C[indx] += variation;
        }
      }
      if ( swit ) {
        pri( "iloop", iloop );
        pri( "epe", epe, MDIM, MDIM );
        pri( "work", work, MDIM, MDIM );
        pri( "C", C, MDIM, MDIM );
        pri( "tmp_stress", tmp_stress, MDIM, MDIM );
      }
      if ( iloop==0 ) 
        array_move( tmp_stress, old_stress, MDIM*MDIM );
      else {
        assert( iloop==1 );
        array_move( tmp_stress, new_stress, MDIM*MDIM );
      }
    }
    array_subtract( new_stress, old_stress, tmp_stress, MDIM*MDIM );
    array_add( new_sig, tmp_stress, new_sig, MDIM*MDIM );

    if ( swit ) pri( "Out HYPERELASTICITY" );

  }

}

void hyper_law( long int hyper_type, double hyper_data[], double C[], 
  double &W )

{
  double I1=0., I2=0., I3=0., J1=0., J2=0., K_1=0., K_2=0., 
    alpha=0., inv_C[MDIM];

  matrix_invariants( C, inv_C ); I1 = inv_C[0]; I2 = inv_C[1]; I3 = inv_C[2]; 
  if ( I3==0. )
    W = 0.;
  else {
    J1 = I1 / pow(I3,1./3.); J2 = I2 / pow(I3,2./3.);
    if ( hyper_type==GROUP_MATERI_HYPER_BESSELING ) {
      K_1 = hyper_data[0];
      K_2 = hyper_data[1];
      alpha = hyper_data[2];
      W = K_1*pow((J1-3.),alpha) + K_2*(J2-3.);
    }
    else {
      assert( hyper_type==GROUP_MATERI_HYPER_MOONEY_RIVLIN );
      K_1 = hyper_data[0];
      K_2 = hyper_data[1];
      W = K_1*(J1-3.) + K_2*(J2-3.);
    }
  }

}
