/*
    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 force_element_volume_set( long int element, long int nnol, long int nodes[], 
  double coord[], double force_element_volume[] )

{
  int i=0, level=0;
  long int j=0, length=0, iforce=0, max_force=0, use_geom=0, nel=0,
    inol=0, inod=0, ok=0, ldum=0, idum[1], *force_element_volume_geometry=NULL;
  double x=0., y=0., factor=1., forcefac=0., rdum=0., ddum[MDIM], 
    force_work[DATA_ITEM_SIZE], *force_element_volume_factor=NULL, 
    *force_element_volume_time=NULL;

  array_set( force_element_volume, 0., npuknwn );

  db_max_index( FORCE_ELEMENT_VOLUME, max_force, VERSION_NORMAL, GET );
  for ( iforce=0; iforce<=max_force; iforce++ ) {
    if ( db_active_index( FORCE_ELEMENT_VOLUME, iforce, VERSION_NORMAL ) ) {
      db( FORCE_ELEMENT_VOLUME, iforce, idum, force_work, ldum, VERSION_NORMAL, GET );
      ok = 1;
      if ( db_active_index( FORCE_ELEMENT_VOLUME_GEOMETRY, iforce, VERSION_NORMAL ) ) {
        force_element_volume_geometry = 
          db_int( FORCE_ELEMENT_VOLUME_GEOMETRY, iforce, VERSION_NORMAL );
        if ( force_element_volume_geometry[0]>0 ) {
          nel = db_len( FORCE_ELEMENT_VOLUME_GEOMETRY, iforce, VERSION_NORMAL );
          ok = array_member( force_element_volume_geometry, element, nel, ldum );
        }
        else {
          use_geom = db_data_class(force_element_volume_geometry[0])==GEOMETRY;
          if ( !use_geom ) db_error( FORCE_ELEMENT_VOLUME_GEOMETRY, iforce );
          for ( inol=0; inol<nnol && ok; inol++ ) {
            inod = nodes[inol];
            geometry( inod, ddum, force_element_volume_geometry, ok, rdum, ddum, rdum,
              ddum, NODE_START_REFINED, PROJECT_EXACT, VERSION_NORMAL );
          }
        }
      }
      if ( ok ) {
        factor = 1.;
        if ( db_active_index( FORCE_ELEMENT_VOLUME_FACTOR, iforce, VERSION_NORMAL ) ) {
          length = db_len( FORCE_ELEMENT_VOLUME_FACTOR, iforce, VERSION_NORMAL );
          force_element_volume_factor = 
            db_dbl( FORCE_ELEMENT_VOLUME_FACTOR, iforce, VERSION_NORMAL );
          if ( ndim==1 ) {
            x = coord[0];
            factor = force_element_volume_factor[0];
            for ( j=level=1; j<length; level++ ) {
              factor += force_element_volume_factor[j] * pow(x,level); j++;
            }
          }
          else if( ndim==2 ) {
            x = coord[0];
            y = coord[1];
            j = 0;
            factor = force_element_volume_factor[j]; j++;
            for ( level=1; j<length; level++ ) {
              if ( j<length ) {
                factor += force_element_volume_factor[j] * pow(x,level); j++;
              }
              for ( i=level-1; i>0 && j<length; i-- ) {
                factor += force_element_volume_factor[j] * pow(x,i) * pow(y,level-i); j++;
              }
              if ( j<length ) {
                factor += force_element_volume_factor[j] * pow(y,level); j++;
              }
            }
          }
        }
        forcefac = factor;
        if ( db_active_index( FORCE_ELEMENT_VOLUME_TIME, iforce, VERSION_NORMAL ) ) {
          length = db_len( FORCE_ELEMENT_VOLUME_TIME, iforce, VERSION_NORMAL );
          if ( length<4 ) db_error( FORCE_ELEMENT_VOLUME_TIME, iforce );
          force_element_volume_time = db_dbl( FORCE_ELEMENT_VOLUME_TIME, iforce, VERSION_NORMAL );
          force_time( force_element_volume_time, length, factor );
          forcefac *= factor;
        }
        array_multiply( force_work, force_work, forcefac, npuknwn );
        array_add( force_work, force_element_volume, force_element_volume, npuknwn );
      }
    }
  }

}

long int force_time( double time_table[], long int length, double &load )

{
  long int inc=0, ninc=0, found=0, ldum=0, idum[1];
  double dtime=0., time_current=0., total_time=0., time0=0., load0=0., 
    time1=0., load1=0.;

  db( DTIME, 0, idum, &dtime, ldum, VERSION_NEW, GET_IF_EXISTS );
  db( TIME_CURRENT, 0, idum, &time_current, ldum, VERSION_NORMAL, GET_IF_EXISTS );
  total_time = time_current + dtime;

  ninc = length / 2; found = 0; load = 0.;
  for ( inc=0; !found && inc<ninc-1; inc++ ) {
    time0 = time_table[inc*2+0];
    load0 = time_table[inc*2+1];
    time1 = time_table[inc*2+2];
    load1 = time_table[inc*2+3];
    if ( total_time>=(time0-1.e-10) && total_time<=time1 ) {
      found = 1;
      if ( time0==time1 ) 
        load = load0;
      else 
        load = load0 + (load1-load0)*(total_time-time0)/(time1-time0);
    }
  }
  if ( !found ) load = 1.;

  return found;
}
