!DEC$ FREEFORM
MODULE type_Step
    
    USE ABQinterface
    
    PUBLIC
    
    TYPE Stepinfo
        CHARACTER(LEN=80):: StepName
        INTEGER:: nlgeom !==1 geometrically nonlinear, ==0 otherwise
        REAL(KIND=AbqRK):: time_end,time_inc_begin, time_inc_max, time_inc_min
        REAL(KIND=AbqRK),DIMENSION(:,:),ALLOCATABLE:: STRAN,STRESS 
        REAL(KIND=AbqRK),DIMENSION(:,:,:),ALLOCATABLE:: DFGRD1
        REAL(KIND=AbqRK),DIMENSION(:),ALLOCATABLE:: timesteps
        CHARACTER(LEN=6):: strain_measure,simulation_type
    END TYPE Stepinfo

END MODULE type_Step

MODULE type_trainingparameters
    !this module defines an object, which comprises all informations about
    !the trainingdirections to be simulated
    
    USE type_Step
    USE ABQinterface
    
    PUBLIC

    TYPE trainingparameters
        CHARACTER(LEN=80):: Material_Name,Jobname
        REAL(KIND=AbqRK),DIMENSION(:),ALLOCATABLE:: PROPS
        INTEGER:: NSTATV
        INTEGER:: NDI,NSHR,NTENS
        TYPE(Stepinfo),DIMENSION(:),ALLOCATABLE:: Step
        CONTAINS
            PROCEDURE:: read_data => read_data_procedure
    END TYPE trainingparameters
    
    TYPE(trainingparameters):: training
    
    CONTAINS
    
        SUBROUTINE read_data_procedure(training)
    
            IMPLICIT NONE
            
            CLASS(trainingparameters):: training
            TYPE(Stepinfo),DIMENSION(:),ALLOCATABLE:: temp_Step
            REAL(KIND=AbqRK),DIMENSION(:,:,:),ALLOCATABLE:: temp_DFGRD1
            REAL(KIND=AbqRK),DIMENSION(:,:),ALLOCATABLE:: temp_STRESS,temp_STRAN
            REAL(KIND=AbqRK),DIMENSION(:),ALLOCATABLE:: temp_timesteps
            REAL(KIND=AbqRK),DIMENSION(4):: time_stepping
            INTEGER:: k,l,n,error
            CHARACTER(len=100):: Keyword
            CHARACTER(len=100),DIMENSION(:),ALLOCATABLE:: Keywords,temp_Keywords
            CHARACTER(len=100),DIMENSION(:),ALLOCATABLE:: Keywords_STEP,temp_Keywords_STEP
            CHARACTER(len=100),DIMENSION(5):: necessary_Keywords=['*MATERIAL','*DEPVAR','*NDI','*NSHR','*STEP']
            CHARACTER(len=100),DIMENSION(3):: necessary_Keywords_Step=['*NAME','*NLGEOM','*STATIC']
            CHARACTER(len=100),DIMENSION(3):: optional_Keywords_Step=['*DFGRD','*STRAN','*STRESS']
            
            !initilization to deal with Materials which set *Depvar=0
            training%NSTATV=0
            
            OPEN(UNIT=26,FILE=TRIM(training%Jobname)//'.inp',STATUS='old',ACTION='READ',IOSTAT=error) !open the file
            
            ALLOCATE(Keywords(0))
            
            IF (error==0) THEN
                DO WHILE (.true.) !go through all lines of the Inputfile
                    READ(26,*,iostat=error) Keyword
                    IF (error/=0) EXIT
                    CALL To_upper(Keyword) !convert to upper cases
                    IF (Keyword(1:1)=='*' .AND. Keyword(2:2)/='*') THEN
                        CALL MOVE_ALLOC(Keywords,temp_Keywords); ALLOCATE(Keywords(size(temp_Keywords)+1)); Keywords(1:size(temp_Keywords))=temp_Keywords
                        Keywords(size(Keywords))=TRIM(Keyword)
                        SELECT CASE(TRIM(Keyword)) !select the current statement
                        CASE('*MATERIAL')
                            READ(26,*,iostat=error) training%Material_Name
                            READ(26,*,iostat=error) n
                            ALLOCATE(training%PROPS(n))
                            READ(26,*,iostat=error) training%PROPS
                        CASE('*DEPVAR')
                            READ(26,*,iostat=error) training%NSTATV
                        CASE('*NDI')
                            READ(26,*,iostat=error) training%NDI
                            training%NTENS=training%NDI+training%NSHR
                        CASE('*NSHR')
                            READ(26,*,iostat=error) training%NSHR
                            training%NTENS=training%NDI+training%NSHR
                        CASE('*STEP')
                            IF (ALLOCATED(training%Step)) THEN
                                CALL MOVE_ALLOC(training%Step,temp_Step)
                                ALLOCATE(training%Step(size(temp_Step)+1))
                                training%Step(:size(temp_Step))=temp_Step
                            ELSE    
                                ALLOCATE(training%Step(1))
                            END IF
                            ALLOCATE(Keywords_STEP(0))
                            DO WHILE (.true.)
                                READ(26,*,iostat=error) Keyword
                                IF (error/=0) EXIT
                                CALL To_upper(Keyword) !convert to upper cases
                                CALL MOVE_ALLOC(Keywords_STEP,temp_Keywords_STEP); ALLOCATE(Keywords_STEP(size(temp_Keywords_STEP)+1)); Keywords_STEP(1:size(temp_Keywords_STEP))=temp_Keywords_STEP
                                Keywords_STEP(size(Keywords_STEP))=TRIM(Keyword)
                                SELECT CASE(TRIM(Keyword))
                                CASE('*NAME')
                                    READ(26,*,iostat=error) training%Step(size(training%Step))%StepName
                                CASE('*NLGEOM')
                                    READ(26,*,iostat=error) Keyword
                                    CALL To_upper(Keyword) !convert to upper cases
                                    IF (Keyword=='YES') THEN
                                        training%Step(size(training%Step))%nlgeom=1
                                    ELSE IF (Keyword=='NO') THEN
                                        training%Step(size(training%Step))%nlgeom=0
                                    ELSE
                                        CALL report_error('Error: An unrecognized Keyword has been found in the UMAT_Driver Inputfile.')
                                    END IF
                                CASE('*STATIC')
                                    READ(26,*,iostat=error) time_stepping
                                    training%Step(size(training%Step))%time_inc_begin=time_stepping(1)
                                    training%Step(size(training%Step))%time_end=time_stepping(2)
                                    training%Step(size(training%Step))%time_inc_min=time_stepping(3)
                                    training%Step(size(training%Step))%time_inc_max=time_stepping(4)
                                CASE('*DFGRD')
                                    training%Step(size(training%Step))%strain_measure='DFGRD1'
                                    training%Step(size(training%Step))%simulation_type='strain'
                                    DO WHILE (.true.)
                                        READ(26,*,iostat=error) Keyword
                                        BACKSPACE(UNIT=26)
                                        IF (Keyword(1:1)=='*') THEN
                                            EXIT
                                        ELSE
                                            IF (ALLOCATED(training%Step(size(training%Step))%DFGRD1)) THEN
                                                CALL MOVE_ALLOC(training%Step(size(training%Step))%DFGRD1,temp_DFGRD1)
                                                ALLOCATE(training%Step(size(training%Step))%DFGRD1(3,3,size(temp_DFGRD1,3)+1))
                                                training%Step(size(training%Step))%DFGRD1(:,:,:size(temp_DFGRD1,3))=temp_DFGRD1
                                                CALL MOVE_ALLOC(training%Step(size(training%Step))%timesteps,temp_timesteps)
                                                ALLOCATE(training%Step(size(training%Step))%timesteps(size(temp_timesteps)+1))
                                                training%Step(size(training%Step))%timesteps(:size(temp_timesteps))=temp_timesteps
                                            ELSE
                                                ALLOCATE(training%Step(size(training%Step))%DFGRD1(3,3,1))
                                                ALLOCATE(training%Step(size(training%Step))%timesteps(1))
                                            END IF
                                            READ(26,*,iostat=error) training%Step(size(training%Step))%timesteps(size(training%Step(size(training%Step))%timesteps))
                                            READ(26,*,iostat=error) training%Step(size(training%Step))%DFGRD1(:,:,size(training%Step(size(training%Step))%DFGRD1,3))
                                        END IF
                                    END DO
                                CASE('*STRAN')
                                    training%Step(:size(training%Step))%strain_measure='DSTRAN'
                                    training%Step(:size(training%Step))%simulation_type='strain'
                                    DO WHILE (.true.)
                                        READ(26,*,iostat=error) Keyword
                                        BACKSPACE(UNIT=26)
                                        IF (Keyword(1:1)=='*') THEN
                                            EXIT
                                        ELSE
                                            IF (ALLOCATED(training%Step(size(training%Step))%STRAN)) THEN
                                                CALL MOVE_ALLOC(training%Step(size(training%Step))%STRAN,temp_STRAN)
                                                ALLOCATE(training%Step(size(training%Step))%STRAN(training%NTENS,size(temp_STRAN,2)+1))
                                                training%Step(size(training%Step))%STRAN(:,:size(temp_STRAN,2))=temp_STRAN
                                                CALL MOVE_ALLOC(training%Step(size(training%Step))%timesteps,temp_timesteps)
                                                ALLOCATE(training%Step(size(training%Step))%timesteps(size(temp_timesteps)+1))
                                                training%Step(size(training%Step))%timesteps(:size(temp_timesteps))=temp_timesteps
                                            ELSE
                                                ALLOCATE(training%Step(size(training%Step))%STRAN(training%NTENS,1))
                                                ALLOCATE(training%Step(size(training%Step))%timesteps(1))
                                            END IF
                                            READ(26,*,iostat=error) training%Step(size(training%Step))%timesteps(size(training%Step(size(training%Step))%timesteps))
                                            READ(26,*,iostat=error) training%Step(size(training%Step))%STRAN(:,size(training%Step(size(training%Step))%STRAN,2))
                                        END IF
                                    END DO
                                CASE('*STRESS')
                                    training%Step(:size(training%Step))%simulation_type='stress'
                                    DO WHILE (.true.)
                                        READ(26,*,iostat=error) Keyword
                                        BACKSPACE(UNIT=26)
                                        IF (Keyword(1:1)=='*') THEN
                                            EXIT
                                        ELSE
                                            IF (ALLOCATED(training%Step(size(training%Step))%STRESS)) THEN
                                                CALL MOVE_ALLOC(training%Step(size(training%Step))%STRESS,temp_STRESS)
                                                ALLOCATE(training%Step(size(training%Step))%STRESS(training%NTENS,size(temp_STRESS,2)+1))
                                                training%Step(size(training%Step))%STRESS(:,:size(temp_STRESS,2))=temp_STRESS
                                                CALL MOVE_ALLOC(training%Step(size(training%Step))%timesteps,temp_timesteps)
                                                ALLOCATE(training%Step(size(training%Step))%timesteps(size(temp_timesteps)+1))
                                                training%Step(size(training%Step))%timesteps(:size(temp_timesteps))=temp_timesteps
                                            ELSE
                                                ALLOCATE(training%Step(size(training%Step))%STRESS(training%NTENS,1))
                                                ALLOCATE(training%Step(size(training%Step))%timesteps(1))
                                            END IF
                                            READ(26,*,iostat=error) training%Step(size(training%Step))%timesteps(size(training%Step(size(training%Step))%timesteps))
                                            READ(26,*,iostat=error) training%Step(size(training%Step))%STRESS(:,size(training%Step(size(training%Step))%STRESS,2))
                                        END IF
                                    END DO
                                CASE('*END_STEP')
                                    EXIT
                                CASE DEFAULT
                                    CALL report_error('Error: An unrecognized Keyword has been found in the UMAT_Driver Inputfile.')
                                END SELECT
                            END DO
                            
                            !check Stepdefinition - all necessary keywords shall be present
                            DO k=1,SIZE(necessary_Keywords_Step)
                                IF (NOT(ANY(Keywords_STEP==necessary_Keywords_Step(k)))) THEN
                                    CALL report_error('Error: Keyword '//TRIM(necessary_Keywords_Step(k))//' missing in a Stepdefinition.')
                                END IF
                            END DO
                            
                            !check Stepdefinition - either STRESS, STRAN or DFGRD shall be present
                            n=0
                            DO k=1,SIZE(optional_Keywords_Step)
                                DO l=1,SIZE(Keywords_STEP)
                                    IF (Keywords_STEP(l)==optional_Keywords_Step(k)) n=n+1
                                END DO
                            END DO
                            IF (.NOT. n==1) THEN
                                CALL report_error('Error: In a Stepdefinition either specify STRESS, STRAN or DFGRD.')
                            END IF
                            DEALLOCATE(Keywords_STEP,temp_Keywords_STEP)
                            
                        CASE DEFAULT
                            CALL report_error('Error: An unrecognized Keyword has been found in the UMAT_Driver Inputfile.')
                        END SELECT
                    END IF
                END DO
            ELSE
                CALL report_error('Error: Could not find the specified Inputfile..')
            END IF
            
            CLOSE (unit=26) !close file
            
            !check inputfile
            DO k=1,SIZE(necessary_Keywords)
                n=0
                DO l=1,SIZE(Keywords)
                    IF (Keywords(l)==necessary_Keywords(k)) n=n+1
                END DO
                IF (n==0) THEN
                    CALL report_error('Error: Keyword '//TRIM(necessary_Keywords(k))//' not found.')
                ELSE IF ((n>1) .AND. (.NOT. (necessary_Keywords(k)=='*STEP'))) THEN
                    CALL report_error('Error: Keyword '//TRIM(necessary_Keywords(k))//' defined more then once.')
                END IF
            END DO
            DEALLOCATE(Keywords)
        
        END SUBROUTINE read_data_procedure
        
        SUBROUTINE report_error(message)
        !output an message and stop the simultation if an error has been found in the Inputfile
        
            IMPLICIT NONE
            
            CHARACTER(LEN=*):: message
        
            WRITE(6,*) TRIM(ADJUSTL(message))
            STOP 'UMAT_Driver exited with errors, look in the .dat or .msg file for possible reasons' 
        
        END SUBROUTINE report_error
        
        SUBROUTINE To_upper(str)
        !this subroutine converts a string with upper and lower cases to a purely
        !upper case expression
            
            IMPLICIT NONE
            
            CHARACTER(*), INTENT(IN OUT) :: str
            INTEGER :: i
        
            DO i = 1, LEN(str)
            SELECT CASE(str(i:i))
                CASE("a":"z")
                str(i:i) = ACHAR(IACHAR(str(i:i))-32)
            END SELECT
            END DO 
        END SUBROUTINE To_upper

END MODULE type_trainingparameters
