/*
    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 EPS_H 1.e-8

void materi( long int element, long int gr, long int nnol, 
  long int npoint, double coord_ip[], double old_coord[],
  double h[], double new_d[], double new_b[], double new_bnl[],
  double volume, double old_unknowns[], 
  double new_unknowns[], double old_grad_old_unknowns[], 
  double old_grad_new_unknowns[], double new_grad_new_unknowns[],
  double element_lhside[], double element_matrix[],
  double element_matrix_stress_stiffness[],
  double element_rhside[], double element_rhside_internal[],
  double element_rhside_static[], double element_residue[], 
  double tendon_element_rhside[] )

{
  long int i=0, j=0, idim=0, jdim=0, kdim=0,
    inol=0, jnol=0, m=0, indx=0, ipuknwn=0, iuknwn=0, jpuknwn=0, 
    swit=0, indxi=0, indxj=0, indx1=0, indx2=0, iteration=0, memory=-UPDATED, 
    ind_ddsdde=0, length=0, ldum=0, idum[1];
  double dens=0., dtime=0., materi_expansion_linear=0., 
    materi_expansion_volume=0., temp=0., tmp=0., damping=0., fac=0, 
    plasti_heat_generation=0., viscosity=0., factor=0.,
    old_damage=0., new_damage=0., old_kappa=0., new_kappa=0., void_fraction=0., rdum=0., 
    ddum[1], gravity[MDIM], old_epe[MDIM*MDIM], inc_epe[MDIM*MDIM], 
    inc_epp[MDIM*MDIM], old_ept[MDIM*MDIM], inc_ept[MDIM*MDIM], 
    old_rot[MDIM*MDIM], inc_rot[MDIM*MDIM], new_rot[MDIM*MDIM], 
    inv_rot[MDIM*MDIM], old_sig[MDIM*MDIM], rot[MDIM*MDIM], 
    new_sig[MDIM*MDIM], rotated_old_sig[MDIM*MDIM], rotated_new_sig[MDIM*MDIM], 
    rotated_old_rho[MDIM*MDIM], rotated_new_rho[MDIM*MDIM], 
    rotated_old_msig[MMAXWELL*MDIM*MDIM], rotated_new_msig[MMAXWELL*MDIM*MDIM], 
    old_msig[MMAXWELL*MDIM*MDIM], new_msig[MMAXWELL*MDIM*MDIM],
    old_rho[MDIM*MDIM], new_rho[MDIM*MDIM], old_hisv[MUKNWN], new_hisv[MUKNWN],
    ddsdde[MSTRAIN*MSTRAIN], ddsdde_tendon[MSTRAIN*MSTRAIN],
    ddsdde_total[MSTRAIN*MSTRAIN], sigvec[MSTRAIN], *sigmat=NULL,
    *work=NULL, *stiffness=NULL, *stress_stiffness=NULL, *force=NULL,
    *gravity_time=NULL;

  swit = set_swit(element,-1,"materi");
  if ( swit ) pri( "In routine MATERI." );

  work = get_new_dbl( MNOL*MDIM*MNOL*MDIM );
  stiffness = get_new_dbl( nnol*ndim*nnol*ndim );
  stress_stiffness = get_new_dbl( nnol*ndim*nnol*ndim );
  force = get_new_dbl( nnol*ndim );
  sigmat = get_new_dbl(  MDIM*MDIM*MDIM*MDIM );

  db( NUMBER_ITERATIONS, 0, &iteration, ddum, ldum, VERSION_NORMAL, GET );
  db( DTIME, 0, idum, &dtime, ldum, VERSION_NEW, GET );
  db( GROUP_MATERI_MEMORY, gr, &memory, ddum, ldum, VERSION_NORMAL, GET_IF_EXISTS );
  get_group_data( GROUP_MATERI_DAMPING, gr, new_unknowns, &damping, ldum, GET_IF_EXISTS );
  get_group_data( GROUP_MATERI_VISCOSITY, gr, new_unknowns, &viscosity, ldum, GET_IF_EXISTS );
  get_group_data( GROUP_MATERI_PLASTI_HEAT_GENERATION, gr, new_unknowns, 
    &plasti_heat_generation, ldum, GET_IF_EXISTS );
  db( GROUP_MATERI_MEMORY, gr, &memory, ddum, ldum, VERSION_NORMAL, GET_IF_EXISTS );
  if ( materi_density ) {
    dens = new_unknowns[dens_indx];
    if ( dens<0. ) dens = 0.;
  }
  else
    get_group_data( GROUP_MATERI_DENSITY, gr, new_unknowns, &dens, ldum, GET_IF_EXISTS );
  if ( db_active_index( FORCE_GRAVITY, 0, VERSION_NORMAL ) ) {
    db( FORCE_GRAVITY, 0, idum, gravity, ldum, VERSION_NORMAL, GET );
    if ( db_active_index( FORCE_GRAVITY_TIME, 0, VERSION_NORMAL ) ) {
      length = db_len( FORCE_GRAVITY_TIME, 0, VERSION_NORMAL );
      if ( length<4 ) db_error( FORCE_GRAVITY_TIME, -1 );
      gravity_time = db_dbl( FORCE_GRAVITY_TIME, 0, VERSION_NORMAL );
      force_time( gravity_time, length, factor );
      for ( idim=0; idim<ndim; idim++ ) gravity[idim] *= factor;
    }
  }
  else
    array_set( gravity, 0., ndim );

  if ( condif_temperature ) {
    get_group_data( GROUP_MATERI_EXPANSION_VOLUME, gr, new_unknowns, 
      &materi_expansion_volume, ldum, GET_IF_EXISTS );
    get_group_data( GROUP_MATERI_EXPANSION_LINEAR, gr, new_unknowns, 
      &materi_expansion_linear, ldum, GET_IF_EXISTS );
    temp = new_unknowns[temp_indx];
    dens = (1.-materi_expansion_volume*temp) * dens;
  }

    // get old stresses, etc.
  for ( idim=0; idim<MDIM; idim++ ) {
    for ( jdim=0; jdim<MDIM; jdim++ ) {
      indx = idim*MDIM + jdim;
      if ( materi_stress ) old_sig[indx] =
       old_unknowns[stres_indx+stress_indx(idim,jdim)*nder];
      if ( materi_strain_elasti ) old_epe[indx] =
        old_unknowns[epe_indx+stress_indx(idim,jdim)*nder];
      if ( materi_strain_total ) old_ept[indx] = 
        old_unknowns[ept_indx+stress_indx(idim,jdim)*nder];
      for ( m=0; m<materi_maxwell_stress; m++ ) {
        indx = m*MDIM*MDIM+idim*MDIM+jdim;
        old_msig[indx] = old_unknowns[mstres_indx+
          (m*6+stress_indx(idim,jdim))*nder];
      }
      if ( materi_plasti_rho ) old_rho[indx] =
        old_unknowns[rho_indx+stress_indx(idim,jdim)*nder];
    }
  }
  if ( materi_history_variables ) {
    for ( i=0; i<materi_history_variables; i++ ) {
      iuknwn = hisv_indx + i;
      old_hisv[i] = old_unknowns[iuknwn];
      new_hisv[i] = new_unknowns[iuknwn];
    }
  }
  if ( materi_plasti_kappa ) {
    iuknwn = kap_indx;
    old_kappa = old_unknowns[iuknwn];
    new_kappa = new_unknowns[iuknwn];
  }
  if ( materi_damage ) {
    iuknwn = dam_indx;
    old_damage = old_unknowns[iuknwn];
    new_damage = new_unknowns[iuknwn];
  }

  set_deften_etc( element, gr, nnol, h, old_coord, old_unknowns, 
    new_unknowns, old_grad_old_unknowns, old_grad_new_unknowns, old_ept, 
    inc_ept, old_rot, inc_rot, new_rot );

    // back rotate to old configuration
  if      ( memory==-TOTAL ) {
    if ( !matrix_inverse( old_rot, inv_rot, rdum, MDIM ) ) {
      pri ("Error detected for element ", element );
      pri ("Probably too large distortions." );
    }
    if ( materi_stress ) {
      matrix_abat( inv_rot, old_sig, rotated_old_sig, work, MDIM );
      if ( swit ) pri( "back rotated_old_sig", rotated_old_sig, MDIM, MDIM );
    }
    if ( materi_plasti_rho ) {
      matrix_abat( inv_rot, old_rho, rotated_old_rho, work, MDIM );
      if ( swit ) pri( "back rotated_old_rho", rotated_old_rho, MDIM, MDIM );
    }
    if ( materi_maxwell_stress ) {
      for ( m=0; m<materi_maxwell_stress; m++ ) {
        indx = m*MDIM*MDIM;
        matrix_abat( inv_rot, &old_msig[indx], 
          &rotated_old_msig[indx], work, MDIM );
      }
    }
  }
  else {
    assert( memory==-UPDATED || memory==-UPDATED_WITHOUT_ROTATION );
    if ( materi_stress ) {
      array_move( old_sig, rotated_old_sig, MDIM*MDIM );
      if ( swit ) pri( "old_sig", rotated_old_sig, MDIM, MDIM );
    }
    if ( materi_plasti_rho ) 
      array_move( old_rho, rotated_old_rho, MDIM*MDIM );
    if ( materi_maxwell_stress )
      array_move( old_msig, rotated_old_msig, materi_maxwell_stress*MDIM*MDIM );
  }

    // set stress, strain
  if ( materi_stress ) {
    set_stress( element, gr, coord_ip, old_unknowns, new_unknowns,
      old_grad_old_unknowns, new_grad_new_unknowns,
      rotated_old_sig, new_sig, rotated_old_msig, new_msig, inc_ept,
      old_epe, inc_epe, inc_epp, old_rho, new_rho, old_hisv, new_hisv, 
      old_damage, new_damage, old_kappa, new_kappa, ddsdde );
    tendons( element, gr, nnol, npoint, volume, new_d, old_unknowns, new_unknowns,
      new_rot, inc_ept, tendon_element_rhside, ddsdde_tendon );
    array_add( ddsdde, ddsdde_tendon, ddsdde_total, MSTRAIN*MSTRAIN );
    if ( swit ) pri( "ddsdde_total", ddsdde_total, MSTRAIN, MSTRAIN );
  }

    // rotate to new configuration
  if ( memory==-UPDATED || memory==-TOTAL ) {
    if ( memory==-UPDATED ) 
      array_move( inc_rot, rot, MDIM*MDIM );
    else {
      assert( memory==-TOTAL );
      array_move( new_rot, rot, MDIM*MDIM );
    }
    if ( materi_stress ) {
      matrix_abat( rot, new_sig, rotated_new_sig, work, MDIM );
      array_move( rotated_new_sig, new_sig, MDIM*MDIM );
      if ( swit ) pri( "new_sig", new_sig, MDIM, MDIM );
    }
    if ( materi_plasti_rho ) {
      matrix_abat( rot, new_rho, rotated_new_rho, work, MDIM );
      array_move( rotated_new_rho, new_rho, MDIM*MDIM );
    }
    if ( materi_maxwell_stress ) {
      for ( m=0; m<materi_maxwell_stress; m++ ) {
        indx = m*MDIM*MDIM;
        matrix_abat( rot, &new_msig[indx], &rotated_new_msig[indx], work, MDIM );
      }
      array_move( rotated_new_msig, new_msig, materi_maxwell_stress*MDIM*MDIM );
    }
  }

  if ( materi_stress ) {
    for ( idim=0; idim<MDIM; idim++ ) {
      for ( jdim=idim; jdim<MDIM; jdim++ ) {
        indx = stress_indx(idim,jdim);
        sigvec[indx] = new_sig[idim*MDIM+jdim];
      }
    }
    matrix_atb( new_b, sigvec, force, MSTRAIN, nnol*ndim, 1 );
    matrix_atba( new_b, ddsdde_total, stiffness, work, MSTRAIN, nnol*ndim );
    sigmat_fill( sigvec, sigmat );
    matrix_atba( new_bnl, sigmat, stress_stiffness, work, MDIM*MDIM, nnol*ndim );
    if ( swit ) {
      pri( "force", force, nnol*ndim );
      pri( "stiffness", stiffness, nnol*ndim, nnol*ndim );
      pri( "sigvec", sigvec, MSTRAIN );
      pri( "new_bnl", new_bnl, MDIM*MDIM, nnol*ndim );
      pri( "sigmat", sigmat, MDIM*MDIM, MDIM*MDIM );
      pri( "stress_stiffness", stress_stiffness, nnol*ndim, nnol*ndim );
    }
  }

    // add to right hand side and left hand side
  fac = ((double)nnol)/2.;
  for ( inol=0; inol<nnol; inol++ ) {

      // velocity
    for ( idim=0; idim<ndim; idim++ ) {
      ipuknwn = vel_indx/nder+idim;
      indx = inol*npuknwn + ipuknwn;
      indxi = inol*npuknwn + ipuknwn;
      iuknwn = vel_indx + idim*nder;
        // damping
      tmp = - h[inol] * damping * new_grad_new_unknowns[idim*nuknwn+iuknwn];
      element_rhside[indx] += volume * tmp;
      element_rhside_internal[indx] -= volume * tmp;
      if ( residue ) element_residue[indx] -= tmp;
      for ( jnol=0; jnol<nnol; jnol++ ) {
        indxj = jnol*npuknwn + ipuknwn;
        tmp = volume * h[inol] * damping * new_d[idim*nnol+jnol];
        element_matrix[indxi*nnol*npuknwn+indxj] += tmp;
        if ( jnol==inol ) element_lhside[indx] += tmp;
      }
        // gravity
      tmp = h[inol] * dens * gravity[idim];
      element_rhside[indx] += volume * tmp;
      element_rhside_internal[indx] -= volume * tmp;
      element_rhside_static[indx] -= volume * tmp;
      if ( residue ) element_residue[indx] -= tmp;
      if ( materi_stress ) {
          // stress gradient (rhside with green partial integration)
        tmp = force[inol*ndim+idim];
        element_rhside[indx] -= volume * tmp;
        element_rhside_internal[indx] += volume * tmp;
        element_rhside_static[indx] += volume * tmp;
        for ( jdim=0; jdim<ndim; jdim++ ) {
          iuknwn = stres_indx+stress_indx(idim,jdim)*nder;
          if ( residue ) element_residue[indx] += h[inol] *
            new_grad_new_unknowns[jdim*nuknwn+iuknwn];
        }
        for ( jnol=0; jnol<nnol; jnol++ ) {
            // groundflow
          if ( groundflow_pressure ) {
            jpuknwn = pres_indx/nder;
            indxj = jnol*npuknwn + jpuknwn;
            tmp = volume * new_d[idim*nnol+inol] * -h[jnol];
            element_matrix[indxi*nnol*npuknwn+indxj] += tmp;
          }
              // temperature stiffness
          if ( condif_temperature ) {
            for ( kdim=0; kdim<ndim; kdim++ ) {
              jpuknwn = temp_indx/nder;
              indxj = jnol*npuknwn + jpuknwn;
              i = stress_indx(idim,idim);
              j = stress_indx(kdim,kdim);
              ind_ddsdde = i*MSTRAIN+j;
              tmp = volume * materi_expansion_linear * new_d[idim*nnol+inol] *
                 -h[jnol] * ddsdde[ind_ddsdde];
              element_matrix[indxi*nnol*npuknwn+indxj] += tmp;
            }
          }
          for ( jdim=0; jdim<ndim; jdim++ ) {
              // stiffness
            indx1 = inol*ndim + idim;
            indx2 = jnol*ndim + jdim;
            jpuknwn = vel_indx/nder + jdim;
            indxj = jnol*npuknwn + jpuknwn;
            tmp = volume * dtime * stiffness[indx1*nnol*ndim+indx2];
            element_matrix[indxi*nnol*npuknwn+indxj] += tmp;
            if ( indxi==indxj ) element_lhside[indx] += fac * tmp;
            tmp = volume * dtime * stress_stiffness[indx1*nnol*ndim+indx2];
            element_matrix_stress_stiffness[indxi*nnol*npuknwn+indxj] += tmp;
              // viscosity
            jpuknwn = vel_indx/nder + jdim;
            indxj = jnol*npuknwn + jpuknwn;
            tmp = volume * new_d[jdim*nnol+inol] * viscosity * new_d[idim*nnol+jnol];
            element_matrix[indxi*nnol*npuknwn+indxj] += tmp;
            if ( idim==jdim && inol==jnol ) element_lhside[indx] += fac * tmp;
            jpuknwn = vel_indx/nder + idim;
            indxj = jnol*npuknwn + jpuknwn;
            tmp = volume * new_d[jdim*nnol+inol] * viscosity * new_d[jdim*nnol+jnol];
            element_matrix[indxi*nnol*npuknwn+indxj] += tmp;
            if ( idim==jdim && inol==jnol ) element_lhside[indx] += fac * tmp;
          }
        }
      }
    }

    if ( scalar_dabs(h[inol])>EPS_H ) {

      if ( materi_history_variables ) {
        for ( i=0; i<materi_history_variables; i++ ) {
          ipuknwn = hisv_indx/nder + i;
          indx = inol*npuknwn + ipuknwn;
          tmp = h[inol] * ( new_hisv[i] - old_hisv[i] ) / dtime;
          element_rhside[indx] += volume * tmp;
          element_rhside_internal[indx] -= volume * tmp;
          element_rhside_static[indx] -= volume * tmp;
          ipuknwn++;
        }
      }

      if ( materi_damage ) {
        ipuknwn = dam_indx/nder;
        indx = inol*npuknwn + ipuknwn;
        tmp = h[inol] * ( new_damage - old_damage ) / dtime;
        element_rhside[indx] += volume * tmp;
        element_rhside_internal[indx] -= volume * tmp;
        element_rhside_static[indx] -= volume * tmp;
      }

      if ( materi_stress ) {
        ipuknwn = stres_indx/nder;
        for ( idim=0; idim<MDIM; idim++ ) {
          for ( jdim=idim; jdim<MDIM; jdim++ ) {
            indx = inol*npuknwn + ipuknwn;
            tmp = h[inol] * ( new_sig[idim*MDIM+jdim] - 
              old_sig[idim*MDIM+jdim] ) / dtime;
            element_rhside[indx] += volume * tmp;
            element_rhside_internal[indx] -= volume * tmp;
            element_rhside_static[indx] -= volume * tmp;
            ipuknwn++;
          }
        }
      }

      if ( materi_plasti_kappa ) {
        ipuknwn = kap_indx/nder;
        indx = inol*npuknwn + ipuknwn;
        tmp = h[inol] * ( new_kappa - old_kappa ) / dtime;
        element_rhside[indx] += volume * tmp;
        element_rhside_internal[indx] -= volume * tmp;
        element_rhside_static[indx] -= volume * tmp;
      }

      if ( materi_plasti_rho ) {
        ipuknwn = rho_indx/nder;
        for ( idim=0; idim<MDIM; idim++ ) {
          for ( jdim=idim; jdim<MDIM; jdim++ ) {
            indx = inol*npuknwn + ipuknwn;
            tmp = h[inol] * ( new_rho[idim*MDIM+jdim] - 
              old_rho[idim*MDIM+jdim] ) / dtime;
            element_rhside[indx] += volume * tmp;
            element_rhside_internal[indx] -= volume * tmp;
            element_rhside_static[indx] -= volume * tmp;
            ipuknwn++;
          }
        }
      }

      if ( materi_strain_elasti ) {
        ipuknwn = epe_indx/nder;
        for ( idim=0; idim<MDIM; idim++ ) {
          for ( jdim=idim; jdim<MDIM; jdim++ ) {
            indx = inol*npuknwn + ipuknwn;
            tmp = h[inol] * inc_epe[idim*MDIM+jdim] / dtime;
            element_rhside[indx] += volume * tmp;
            element_rhside_internal[indx] -= volume * tmp;
            element_rhside_static[indx] -= volume * tmp;
            ipuknwn++;
          }
        }
      }

      if ( materi_strain_plasti ) {
        ipuknwn = epp_indx/nder;
        for ( idim=0; idim<MDIM; idim++ ) {
          for ( jdim=idim; jdim<MDIM; jdim++ ) {
            indx = inol*npuknwn + ipuknwn;
            tmp = h[inol] * inc_epp[idim*MDIM+jdim] / dtime;
            element_rhside[indx] += volume * tmp;
            element_rhside_internal[indx] -= volume * tmp;
            element_rhside_static[indx] -= volume * tmp;
            ipuknwn++;
          }
        }
        if ( condif_temperature ) {
          ipuknwn = temp_indx/nder;
          indx = inol*npuknwn + ipuknwn;
          tmp = plasti_heat_generation * h[inol] *
            array_inproduct( new_sig, inc_epp, MDIM*MDIM ) / dtime;
          element_rhside[indx] += volume * tmp;
          element_rhside_internal[indx] -= volume * tmp;
          element_rhside_static[indx] -= volume * tmp;
          element_residue[indx] -= tmp;
        }
      }

      if ( materi_strain_total ) {
        ipuknwn = ept_indx/nder;
        for ( idim=0; idim<MDIM; idim++ ) {
          for ( jdim=idim; jdim<MDIM; jdim++ ) {
            indx = inol*npuknwn + ipuknwn;
            tmp = h[inol] * inc_ept[idim*MDIM+jdim] / dtime;
            element_rhside[indx] += volume * tmp;
            element_rhside_internal[indx] -= volume * tmp;
            element_rhside_static[indx] -= volume * tmp;
            ipuknwn++;
          }
        }
      }

      if ( materi_maxwell_stress ) {
        ipuknwn = mstres_indx/nder;
        for ( m=0; m<materi_maxwell_stress; m++ ) {
          for ( idim=0; idim<MDIM; idim++ ) {
            for ( jdim=idim; jdim<MDIM; jdim++ ) {
              indx = inol*npuknwn + ipuknwn;
              tmp = h[inol] * ( new_msig[m*MDIM*MDIM+idim*MDIM+jdim] -
                  old_msig[m*MDIM*MDIM+idim*MDIM+jdim] ) / dtime;
              element_rhside[indx] += volume * tmp;
              element_rhside_internal[indx] -= volume * tmp;
              element_rhside_static[indx] -= volume * tmp;
              ipuknwn++;
            }
          }
        }
      }

      if ( materi_void_fraction && materi_strain_plasti ) {
        ipuknwn = void_indx/nder;
        indx = inol*npuknwn + ipuknwn;
        void_fraction = new_unknowns[void_indx];
        tmp = h[inol] * ( 1 - void_fraction ) * void_fraction * ( inc_epp[0*MDIM+0] + 
          inc_epp[1*MDIM+1] + inc_epp[2*MDIM+2] );
        element_rhside[indx] += volume * tmp;
        element_rhside_internal[indx] -= volume * tmp;
        element_rhside_static[indx] -= volume * tmp;
      }

    }

  }

  if ( swit ) {
    pri( "tendon_element_rhside", tendon_element_rhside, nnol, npuknwn );
    pri( "element_lhside", element_lhside, nnol, npuknwn );
    pri( "element_rhside", element_rhside, nnol, npuknwn );
    pri( "element_rhside_internal", element_rhside_internal, nnol, npuknwn );
    pri( "element_rhside_static", element_rhside_static, nnol, npuknwn );
    if ( residue ) pri( "element_residue", element_residue, nnol, npuknwn );
  }

  delete[] work;
  delete[] stiffness;
  delete[] stress_stiffness;
  delete[] force;
  delete[] sigmat;

  if ( swit ) pri( "Out function MATERI" );

}

void set_deften_etc( long int element, long int gr, long int nnol, double h[], 
  double old_coord[], double old_unknowns[], double new_unknowns[], 
  double old_grad_old_unknowns[], double old_grad_new_unknowns[], 
  double old_ept[], double inc_ept[], double old_rot[], double inc_rot[], 
  double new_rot[] )

{
  long int idim=0, jdim=0, kdim=0, indx=0, swit=0, memory=-UPDATED, 
    axisymmetric=-NO, ind=0, ldum=0, idum[1];
  double dtime=0., radius=0., rdum=0., ddum[1], uTu[MDIM*MDIM], val[MDIM], 
    dir[MDIM*MDIM], work[MDIM*MDIM], ept[MDIM*MDIM], old_deften[MDIM*MDIM], 
    inc_deften[MDIM*MDIM], new_deften[MDIM*MDIM], coord_ip[MDIM], 
    work_new_ept[MDIM*MDIM];

  swit = set_swit(element,-1,"set_deften_etc");
  if ( swit ) pri( "In routine SET_DEFTEN_ETC." );

  db( DTIME, 0, idum, &dtime, ldum, VERSION_NEW, GET );
  db( GROUP_MATERI_MEMORY, gr, &memory, ddum, ldum, VERSION_NORMAL, GET_IF_EXISTS );
  db( OPTIONS_AXISYMMETRIC, 0, &axisymmetric, ddum, ldum, VERSION_NORMAL, GET_IF_EXISTS );

  if ( memory==-TOTAL ) {
    array_set( old_deften, 0., MDIM*MDIM ); 
    array_set( new_deften, 0., MDIM*MDIM ); 
    old_deften[0] = old_deften[4] = old_deften[8] = 1.;
    new_deften[0] = new_deften[4] = new_deften[8] = 1.;
    for ( idim=0; idim<ndim; idim++ ) {
      for ( jdim=0; jdim<ndim; jdim++ ) {
        indx = idim*MDIM+jdim;
        old_deften[indx] +=
          old_grad_old_unknowns[jdim*nuknwn+dis_indx+idim*nder];
        new_deften[indx] += 
          old_grad_new_unknowns[jdim*nuknwn+dis_indx+idim*nder];
      }
    }
  }
  else {
    array_set( inc_deften, 0., MDIM*MDIM ); 
    inc_deften[0] = inc_deften[4] = inc_deften[8] = 1.;
    for ( idim=0; idim<ndim; idim++ ) {
      for ( jdim=0; jdim<ndim; jdim++ ) {
        indx = idim*MDIM+jdim;
        ind = jdim*nuknwn+vel_indx+idim*nder;
        inc_deften[indx] += old_grad_new_unknowns[ind]*dtime;
      }
    }
    if ( swit ) pri( "inc_deften", inc_deften, MDIM, MDIM );
  }
  if ( axisymmetric==-YES ) {
    matrix_ab( h, old_coord, coord_ip, 1, nnol, ndim );
    radius = scalar_dabs(coord_ip[0]);
    if ( radius!=0. ) {
      if ( memory==-TOTAL ) {
        ind = dis_indx;
        old_deften[8] += old_unknowns[ind]/radius;
        new_deften[8] += new_unknowns[ind]/radius;
      }
      else {
        ind = vel_indx;
        inc_deften[8] += new_unknowns[ind]*dtime/radius;
      }
    }
  }

      // stretch tensor
  if ( memory==-UPDATED_WITHOUT_ROTATION ) {
    for ( idim=0; idim<MDIM; idim++ ) {
      for ( jdim=0; jdim<MDIM; jdim++ ) inc_ept[idim*MDIM+jdim] = 
        0.5*(inc_deften[idim*MDIM+jdim]+inc_deften[jdim*MDIM+idim]);
    }
    for ( idim=0; idim<MDIM; idim++ ) inc_ept[idim*MDIM+idim] -= 1.;
    if ( materi_strain_total ) array_add( old_ept, inc_ept, work_new_ept, MDIM*MDIM );
  }
  else if ( memory==-UPDATED ) {
    matrix_atb( inc_deften, inc_deften, uTu, MDIM, MDIM, MDIM );
    matrix_jacobi( uTu, MDIM, val, dir, idum );
    for ( idim=0; idim<MDIM; idim++ ) {
      for ( jdim=0; jdim<MDIM; jdim++ ) {
        indx = idim*MDIM+jdim;
        inc_ept[indx] = 0.;
        for ( kdim=0; kdim<MDIM; kdim++ ) inc_ept[indx] += 
          sqrt(scalar_dabs(val[kdim]))*dir[idim*MDIM+kdim]*dir[jdim*MDIM+kdim];
      }
    }
    if ( !matrix_inverse( inc_ept, work, rdum, MDIM ) ) {
      pri ("Error detected for element ", element );
      pri ("Probably too large distortions." );
    }
    matrix_ab( inc_deften, work, inc_rot, MDIM, MDIM, MDIM );
    for ( idim=0; idim<MDIM; idim++ ) inc_ept[idim*MDIM+idim] -= 1.;
    if ( materi_strain_total ) array_add( old_ept, inc_ept, work_new_ept, MDIM*MDIM );
    if ( swit ) pri( "inc_rot", inc_rot, MDIM, MDIM );
  }
  else {
    if ( memory!=-TOTAL ) db_error( GROUP_MATERI_MEMORY, gr );
    matrix_atb( old_deften, old_deften, uTu, MDIM, MDIM, MDIM );
    matrix_jacobi( uTu, MDIM, val, dir, idum );
    for ( idim=0; idim<MDIM; idim++ ) {
      for ( jdim=0; jdim<MDIM; jdim++ ) {
        indx = idim*MDIM+jdim;
        ept[indx] = 0.;
        for ( kdim=0; kdim<MDIM; kdim++ ) ept[indx] += 
          sqrt(scalar_dabs(val[kdim]))*dir[idim*MDIM+kdim]*dir[jdim*MDIM+kdim];
      }
    }
    if ( !matrix_inverse( ept, work, rdum, MDIM ) ) {
      pri ("Error detected for element ", element );
      pri ("Probably too large distortions." );
    }
    matrix_ab( old_deften, work, old_rot, MDIM, MDIM, MDIM );
    matrix_atb( new_deften, new_deften, uTu, MDIM, MDIM, MDIM );
    matrix_jacobi( uTu, MDIM, val, dir, idum );
    for ( idim=0; idim<MDIM; idim++ ) {
      for ( jdim=0; jdim<MDIM; jdim++ ) {
        indx = idim*MDIM+jdim;
        work_new_ept[indx] = 0.;
        for ( kdim=0; kdim<MDIM; kdim++ ) work_new_ept[indx] += 
          sqrt(scalar_dabs(val[kdim]))*dir[idim*MDIM+kdim]*dir[jdim*MDIM+kdim];
      }
    }
    if ( !matrix_inverse( work_new_ept, work, rdum, MDIM ) ) {
      pri ("Error detected for element ", element );
      pri ("Probably too large distortions." );
    }
    matrix_ab( new_deften, work, new_rot, MDIM, MDIM, MDIM );
    for ( idim=0; idim<MDIM; idim++ ) work_new_ept[idim*MDIM+idim] -= 1.;
    array_subtract( work_new_ept, old_ept, inc_ept, MDIM*MDIM );
    if ( swit ) {
      pri( "old_deften", old_deften, MDIM, MDIM );
      pri( "new_deften", new_deften, MDIM, MDIM );
      pri( "old_rot", old_rot, MDIM, MDIM );
      pri( "new_rot", new_rot, MDIM, MDIM );
    }
  }
  if ( swit ) pri( "inc_ept", inc_ept, MDIM, MDIM );

  if ( swit ) pri( "Out function SET_DEFTEN_ETC" );
}

void sigmat_fill( double sigvec[], double sigmat[] )

{
  long int idim=0;
  double work[MDIM*MDIM];

  work[0*MDIM+0] = work[0*MDIM+0] = sigvec[0];
  work[0*MDIM+1] = work[1*MDIM+0] = sigvec[1];
  work[0*MDIM+2] = work[2*MDIM+0] = sigvec[2];
  work[1*MDIM+1] = work[1*MDIM+1] = sigvec[3];
  work[1*MDIM+2] = work[2*MDIM+1] = sigvec[4];
  work[2*MDIM+2] = work[2*MDIM+2] = sigvec[5];

  array_set( sigmat, 0., MDIM*MDIM*MDIM*MDIM );
  for ( idim=0; idim<MDIM; idim++ )
    matrix_insert( work, MDIM, MDIM, sigmat, idim*MDIM, idim*MDIM, MDIM*MDIM );
}
