!-------------------------------------------------------------------------------
! Copyright (c) 2016 The University of Tokyo
! This software is released under the MIT License, see LICENSE.txt
!-------------------------------------------------------------------------------
!> \brief This module provides main suboruitne for nonliear calculation.

module m_fstr_solve_eps2disp
  use m_fstr
  use m_static_lib
  use m_static_output
  use fstr_matrix_con_contact
  use m_fstr_TimeInc
  use m_fstr_StiffMatrix
  use m_fstr_Update
  use m_fstr_ass_load
  use m_fstr_AddBC
  use m_fstr_Residual
  use m_fstr_Restart
  use fstr_setup_util

  implicit none

contains

  subroutine fstr_mesh_eps2disp(hecMESH, hecMAT, fstrSOLID, fstrMAT, fstrPARAM)
    type (hecmwST_local_mesh)             :: hecMESH      !< mesh information
    type (hecmwST_matrix    )             :: hecMAT       !< linear equation, its right side modified here
    type (fstr_param        )             :: fstrPARAM    !< analysis control parameters
    type (fstr_solid        )             :: fstrSOLID    !< we need boundary conditions of curr step
    type (fstrST_matrix_contact_lagrange) :: fstrMAT      !< type fstrST_matrix_contact_lagrange
    integer(kind=kint) :: i, j, in
    integer(kind=kint) :: neps, tot_step, sub_step, stepcnt
    integer(kind=kint) :: NPNDOF, ngp
    integer(kind=kint), pointer :: elemid(:)
    real(kind=kreal) :: t1, t2, etemp(48)
    real(kind=kreal) :: ctime, dtime, etype
    real(kind=kreal) :: tt0, tt, res, qnrm, rres, tincr, xnrm, dunrm, rxnrm
    real(kind=kreal), allocatable :: strain(:,:)
    logical :: isLinear = .false.

    if(hecMESH%my_rank == 0) write(*,*)"fstr_mesh_eps2disp"
    allocate(elemid(1))

    open(60, file="istrain.dat", status="old")
      read(60,*)etype, neps
      ngp = 0
      if(etype == 341) ngp = 6*1
      if(etype == 342) ngp = 6*4
      if(etype == 361) ngp = 6*8

      allocate(strain(ngp,neps))
      elemid = 0
      strain = 0.0d0
      do i = 1, neps
        read(60,*)elemid(1), (etemp(j), j = 1, ngp)
        in = elem_global_to_local(hecMESH, elemid, 1)
        if(elemid(1) < 0) cycle
        strain(1:ngp, elemid(1)) = etemp(1:ngp)
      enddo
    close(60)

    isLinear = .true.
    tot_step = 1
    sub_step = 1
    ctime = fstr_get_time()
    dtime = fstr_get_timeinc()

    call fstr_UpdateState( hecMESH, fstrSOLID, 0.0d0 )

    tincr = 0.d0
    stepcnt = 1
    fstrSOLID%dunode = 0.0d0
    fstrSOLID%NRstat_i = 0
    hecMAT%Iarray(98) = 2
    hecMAT%X = 0.0d0
    NPNDOF = hecMAT%NP*hecMAT%NDOF

    call fstr_StiffMatrix( hecMESH, hecMAT, fstrSOLID, ctime, tincr )

    call fstr_ass_load(stepcnt, ctime, hecMESH, hecMAT, fstrSOLID, fstrPARAM)
    !write(*,*)"B old"
    !write(*,"(1p3e12.5)")hecMAT%B

    call fstr_ass_load_from_strain(hecMESH, hecMAT, fstrSOLID, fstrPARAM, strain)
    !write(*,*)"B"
    !write(*,"(1p3e12.5)")hecMAT%B

    call fstr_AddBC(stepcnt, hecMESH, hecMAT, fstrSOLID, fstrPARAM, fstrMAT, 1)

    call hecmw_update_3_R (hecMESH, hecMAT%B, hecMAT%NP)
    call solve_LINEQ(hecMESH, hecMAT)
    call hecmw_update_3_R (hecMESH, hecMAT%X, hecMAT%NP)


    do i=1, NPNDOF
      fstrSOLID%dunode(i) = fstrSOLID%dunode(i) + hecMAT%X(i)
    enddo

    call fstr_UpdateNewton(hecMESH, hecMAT, fstrSOLID, ctime, tincr, 1)
    call fstr_Update_NDForce(tot_step, hecMESH, hecMAT, fstrSOLID)

    do i=1, NPNDOF
      fstrSOLID%unode(i) = fstrSOLID%unode(i) + fstrSOLID%dunode(i)
    enddo

    call fstr_UpdateState( hecMESH, fstrSOLID, tincr )

    call fstr_static_Output( tot_step, stepcnt, 1.0d0, hecMESH, fstrSOLID, fstrPARAM, kstSTATIC, .true. )
  end subroutine fstr_mesh_eps2disp

  subroutine fstr_mesh_stress2disp(hecMESH, hecMAT, fstrSOLID, fstrMAT, fstrPARAM)
    type (hecmwST_local_mesh)             :: hecMESH      !< mesh information
    type (hecmwST_matrix    )             :: hecMAT       !< linear equation, its right side modified here
    type (fstr_param        )             :: fstrPARAM    !< analysis control parameters
    type (fstr_solid        )             :: fstrSOLID    !< we need boundary conditions of curr step
    type (fstrST_matrix_contact_lagrange) :: fstrMAT      !< type fstrST_matrix_contact_lagrange
    integer(kind=kint) :: i, j, in
    integer(kind=kint) :: nstress, tot_step, sub_step, stepcnt
    integer(kind=kint) :: NPNDOF, ngp
    integer(kind=kint), pointer :: elemid(:)
    real(kind=kreal) :: t1, t2, etemp(48)
    real(kind=kreal) :: ctime, dtime, etype
    real(kind=kreal) :: tt0, tt, res, qnrm, rres, tincr, xnrm, dunrm, rxnrm
    real(kind=kreal), pointer :: coord(:), P(:)
    real(kind=kreal), allocatable :: stress(:,:)
    logical :: isLinear = .false.

    if(hecMESH%my_rank == 0) write(*,*)"fstr_mesh_stress2disp"
    allocate(elemid(1))

    open(60, file="istress.dat", status="old")
      read(60,*)etype, nstress
      ngp = 0
      if(etype == 341) ngp = 6*1
      if(etype == 342) ngp = 6*4
      if(etype == 361) ngp = 6*8

      allocate(stress(ngp, nstress))
      elemid = 0
      stress = 0.0d0
      do i = 1, nstress
        read(60,*)elemid(1), (etemp(j), j = 1, ngp)
        in = elem_global_to_local(hecMESH, elemid, 1)
        if(elemid(1) < 0) cycle
        stress(1:ngp, elemid(1)) = etemp(1:ngp)
      enddo
    close(60)

    isLinear = .true.
    tot_step = 1
    sub_step = 1
    ctime = fstr_get_time()
    dtime = fstr_get_timeinc()

    call fstr_UpdateState( hecMESH, fstrSOLID, 0.0d0 )

    tincr = 0.d0
    stepcnt = 1
    fstrSOLID%dunode = 0.0d0
    fstrSOLID%NRstat_i = 0
    hecMAT%Iarray(98) = 2
    hecMAT%X = 0.0d0
    NPNDOF = hecMAT%NP*hecMAT%NDOF

    call fstr_StiffMatrix( hecMESH, hecMAT, fstrSOLID, ctime, tincr )

    call fstr_ass_load(stepcnt, ctime, hecMESH, hecMAT, fstrSOLID, fstrPARAM)

    call fstr_ass_load_from_stress(hecMESH, hecMAT, fstrSOLID, fstrPARAM, stress)

    call fstr_AddBC(stepcnt, hecMESH, hecMAT, fstrSOLID, fstrPARAM, fstrMAT, 1)

    call hecmw_update_3_R (hecMESH, hecMAT%B, hecMAT%NP)
    call solve_LINEQ(hecMESH, hecMAT)
    call hecmw_update_3_R (hecMESH, hecMAT%X, hecMAT%NP)

    do i = 1, NPNDOF
      fstrSOLID%dunode(i) = fstrSOLID%dunode(i) + hecMAT%X(i)
    enddo

    call fstr_UpdateNewton(hecMESH, hecMAT, fstrSOLID, ctime, tincr, 1)
    call fstr_Update_NDForce(tot_step, hecMESH, hecMAT, fstrSOLID)

    do i = 1, NPNDOF
      fstrSOLID%unode(i) = fstrSOLID%unode(i) + fstrSOLID%dunode(i)
    enddo

    call fstr_UpdateState( hecMESH, fstrSOLID, tincr )

    call fstr_static_Output( tot_step, stepcnt, 1.0d0, hecMESH, fstrSOLID, fstrPARAM, kstSTATIC, .true. )
  end subroutine fstr_mesh_stress2disp

end module m_fstr_solve_eps2disp
