/*     CalculiX - A 3-dimensional finite element program                   */
/*              Copyright (C) 1998-2005 Guido Dhondt                          */

/*     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(version 2);    */
/*                    */

/*     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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.         */

  /* calculating the initial acceleration at the start of the step
     for dynamic calculations */

  if((*nmethod==4)&&(*ithermal!=2)){
    bet=(1.-*alpha)*(1.-*alpha)/4.;
    gam=0.5-*alpha;

    /* calculating the stiffness and mass matrix 
       the stress must be determined to calculate the 
       stiffness matrix*/

    fn=NNEW(double,4**nk);
    stx=NNEW(double,6**mint_**ne);
    if(*ithermal>1) qfx=NNEW(double,3**mint_**ne);
    
    iout=-1;
    time=0.;
    dtime=1.;
    ielas=1;
    
    /*  updating the nonlinear mpc's (also affects the boundary
	conditions through the nonhomogeneous part of the mpc's)
        if contact arises the number of MPC's can also change */

    if(*ithermal>1){FORTRAN(radflowload,(itg,ieg,&ntg,&ntr,&ntm,
       ac,bc,nload,sideload,nelemload,xloadact,lakon,ipiv,ntmat_,vold,
       shcon,nshcon,ipkon,kon,co,pmid,e1,e2,e3,iptri,
       kontri,&ntri,nloadtr,tarea,tenv,physcon,erad,fij,
       dist,idist,area,nflow,ikboun,xboun,nboun,ithermal,&iinc,&iit,
       cs,mcs,inocs,&ntrit,nk,fenv,istep,&dtime,ttime,&time,ilboun,
       ikforc,ilforc,xforcact,nforc,&cam,ielmat));}

    if(icascade==2){
	*nmpc=nmpcref;memmpc_=memmpcref_;mpcfree=mpcfreeref;
	RENEW(nodempc,int,3*memmpcref_);
	for(k=0;k<3*memmpcref_;k++){nodempc[k]=nodempcref[k];}
	RENEW(coefmpc,double,memmpcref_);
	for(k=0;k<memmpcref_;k++){coefmpc[k]=coefmpcref[k];}
    }
    newstep=0;
    FORTRAN(nonlinmpc,(co,vold,ipompc,nodempc,coefmpc,labmpc,
		       nmpc,ikboun,ilboun,nboun,xbounold,aux,iaux,
		       &maxlenmpc,ikmpc,ilmpc,&icascade,
		       kon,ipkon,lakon,ne,&reltime,&newstep,xboun,fmpc,
                       &iit,&idiscon));
    if(icascade==2){
	nmpcref=*nmpc;memmpcref_=memmpc_;mpcfreeref=mpcfree;
	RENEW(nodempcref,int,3*memmpc_);
	for(k=0;k<3*memmpc_;k++){nodempcref[k]=nodempc[k];}
	RENEW(coefmpcref,double,memmpc_);
	for(k=0;k<memmpc_;k++){coefmpcref[k]=coefmpc[k];}
    }

    if(icascade>0) remastruct(ipompc,&coefmpc,&nodempc,nmpc,
              &mpcfree,nodeboun,ndirboun,nboun,ikmpc,ilmpc,ikboun,ilboun,
              labmpc,nk,&memmpc_,&icascade,&maxlenmpc,
              kon,ipkon,lakon,ne,nnn,nactdof,icol,jq,&irow,isolver,
	      neq,nzs,nmethod,&f,&finc,&fext,&b,&aux2,&fini,&fextini,
	      &adb,&aub,ithermal,iperturb);

    FORTRAN(results,(co,nk,kon,ipkon,lakon,ne,vold,stn,inum,stx,
	  elcon,nelcon,rhcon,nrhcon,alcon,nalcon,alzero,ielmat,
	  ielorien,norien,orab,ntmat_,t0,t1old,ithermal,
	  prestr,iprestr,filab,eme,een,iperturb,
	  f,fn,nactdof,&iout,&qa,vold,b,nodeboun,
	  ndirboun,xbounold,nboun,ipompc,
	  nodempc,coefmpc,labmpc,nmpc,nmethod,&cam,&neq[1],veold,accold,&bet,
          &gam,&dtime,&time,ttime,plicon,nplicon,plkcon,nplkcon,
	  xstateini,xstiff,xstate,npmat_,epn,matname,mint_,&ielas,&icmd,
          ncmat_,nstate_,sti,vini,ikboun,ilboun,ener,enern,sti,xstaten,
          eei,enerini,cocon,ncocon,set,nset,istartset,iendset,
          ialset,nprint,prlab,prset,qfx,qfn,trab,inotr,ntrans,fmpc,
          nelemload,nload));
    
    iout=0;
    ielas=0;
    
    free(fn);free(stx);if(*ithermal>1)free(qfx);

    if(*iexpl==0){intscheme=1;}

    ad=NNEW(double,neq[1]);
    au=NNEW(double,nzs[1]);

    FORTRAN(mafillsm,(co,nk,kon,ipkon,lakon,ne,nodeboun,ndirboun,xbounold,nboun,
	      ipompc,nodempc,coefmpc,nmpc,nodeforc,ndirforc,xforcold,
	      nforc,nelemload,sideload,xloadold,nload,xbodyold,ipobody,
	      nbody,cgr,ad,au,finc,fext,nactdof,icol,jq,irow,&neq[1],nzl,
	      &nmethodact,ikmpc,ilmpc,ikboun,ilboun,
	      elcon,nelcon,rhcon,nrhcon,alcon,nalcon,alzero,
	      ielmat,ielorien,norien,orab,ntmat_,
	      t0,t1old,ithermal,prestr,iprestr,vold,iperturb,sti,
	      nzs,stx,adb,aub,iexpl,plicon,nplicon,plkcon,nplkcon,
	      xstiff,npmat_,&dtime,matname,mint_,
              ncmat_,&mass,&stiffness,&buckling,&rhsi,&intscheme,
	      physcon,shcon,nshcon,cocon,ncocon,ttime,&time,istep,&iinc,
              &coriolis));

    if(nmethodact==0){
      
      /* error occurred in mafill: storing the geometry in frd format */

      ++*kode;
    ipneigh=NNEW(int,*nk);neigh=NNEW(int,40**ne);
      FORTRAN(out,(co,nk,kon,ipkon,lakon,ne,v,stn,inum,nmethod,kode,filab,
           een,t1,fn,ttime,epn,ielmat,matname,enern,xstaten,nstate_,istep,
           &iinc,iperturb,ener,mint_,output,ithermal,qfn,&mode,&noddiam,
           trab,inotr,ntrans,orab,ielorien,norien,description,
                     ipneigh,neigh,sti));free(ipneigh);free(neigh);
      
      FORTRAN(stop,());
      
    }

    /* calculating the acceleration at the start of the step.
       This can be different from the acceleration at the end
       of the last step due to a discontinuous loading increase */

    reltime=0.;
    time=0.;
    dtime=0.;

    FORTRAN(tempload,(xforcold,xforc,xforcact,iamforc,nforc,xloadold,xload,
	      xloadact,iamload,nload,ibody,xbody,nbody,xbodyold,xbodyact,
	      t1old,t1,t1act,iamt1,nk,amta,
	      namta,nam,ampli,&time,&reltime,ttime,&dtime,ithermal,nmethod,
              xbounold,xboun,xbounact,iamboun,nboun,
	      nodeboun,ndirboun,nodeforc,ndirforc,istep,&iinc,
	      co,vold));

    /* determining the external loading vector */

    FORTRAN(rhs,(co,nk,kon,ipkon,lakon,ne,
	 ipompc,nodempc,coefmpc,nmpc,nodeforc,ndirforc,xforcact,
	 nforc,nelemload,sideload,xloadact,nload,xbodyact,ipobody,
	 nbody,cgr,fext,nactdof,&neq[1],
	 &nmethodact,ikmpc,ilmpc,
	 elcon,nelcon,rhcon,nrhcon,alcon,nalcon,alzero,
	 ielmat,ielorien,norien,orab,ntmat_,
	 t0,t1act,ithermal,iprestr,vold,iperturb,
	 iexpl,plicon,nplicon,plkcon,nplkcon,
	 npmat_,ttime,&time,istep,&iinc,&dtime,physcon));

    /* mass x acceleration = f(external)-f(internal) */

    for(k=0;k<neq[1];++k){
      b[k]=fext[k]-f[k];
    }

    if(*iexpl==0){

      /* a small amount of stiffness is added to the mass matrix
       otherwise the system leads to huge accelerations in 
       case of discontinuous load changes at the start of the step */

	dtime=*tinc/10.;
	scal1=bet*dtime*dtime*(1.+*alpha);
	for(k=0;k<neq[1];++k){
	    /*ad[k]=adb[k];*/
	    ad[k]=adb[k]+scal1*ad[k];
	}
	for(k=0;k<nzs[1];++k){
	    /*au[k]=aub[k];*/
	    au[k]=aub[k]+scal1*au[k];
	}
        if(*isolver==0){
#ifdef SPOOLES
          spooles(ad,au,adb,aub,&sigma,b,icol,irow,&neq[1],&nzs[1]);
#else
          printf("*ERROR in nonlingeo: the SPOOLES library is not linked\n\n");
          FORTRAN(stop,());
#endif
        }
        else if((*isolver==2)||(*isolver==3)){
          preiter(ad,&au,b,&icol,&irow,&neq[1],&nzs[1],isolver,iperturb);
        }
        else if(*isolver==4){
#ifdef SGI
          token=1;
          sgi_main(ad,au,adb,aub,&sigma,b,icol,irow,&neq[1],&nzs[1],token);
#else
          printf("*ERROR in nonlingeo: the SGI library is not linked\n\n");
          FORTRAN(stop,());
#endif
        }
        else if(*isolver==5){
#ifdef TAUCS
          tau(ad,&au,adb,aub,&sigma,b,icol,&irow,&neq[1],&nzs[1]);
#else
          printf("*ERROR in nonlingeo: the TAUCS library is not linked\n\n");
          FORTRAN(stop,());
#endif
        }
    }

    else{
      for(k=0;k<neq[1];++k){
	b[k]=(fext[k]-f[k])/adb[k];
      }
    }

    for(k=0;k<4**nk;++k){
	if(nactdof[k]!=0){accold[k]=b[nactdof[k]-1];}
    }

    free(ad);free(au);
    mass=0;intscheme=0;

  }
