This lightly commented program performs a unit test on the ELL_Matrix Class.
program Unit_Test use Caesar_Data_Structures_Module use Caesar_Mathematic_Vector_Class use Caesar_ELL_Matrix_Class use Caesar_Numbers_Module, only: zero, half, one, two, three, six, ten implicit none type(Communication_type) :: Comm type(Base_Structure_type) :: Row_Structure, Column_Structure type(Status_type) :: status type(character,name_length) :: Locus_Name, ELLM_Name, MV_Name type(integer,1) :: Row_Length_Vector, Rows type(integer,2) :: Columns type(integer) :: shift, first_plus_last_PE_RS type(real,2) :: Values type(real,1) :: X_BNV type(real) :: AvgB, B_Norm2, MaxB, MinB, NRows_real, ResidualNorm1, & ResidualNorm2 type(integer) :: i, j, NRows, MaxNonzeros type(ELL_Matrix_type) :: A_ELLM, B_ELLM type(Mathematic_Vector_type) :: X_MV, B_MV, Residual_MV ! Initializations. call Initialize (Comm) call Output (Comm) call Initialize (status) call Initialize (Locus_Name) call Initialize (ELLM_Name) call Initialize (MV_Name) call Initialize (Row_Length_Vector, NPEs) Row_Length_Vector = (/ (i**2, i = 1, NPEs) /) call Initialize (MaxNonzeros) MaxNonzeros = MIN(5, SUM(Row_Length_Vector)) ! Local temp vectors. call Initialize (Rows, Row_Length_Vector(this_PE)) call Initialize (Values, Row_Length_Vector(this_PE), MaxNonzeros) call Initialize (Columns, Row_Length_Vector(this_PE), MaxNonzeros) call Initialize (X_BNV, Row_Length_Vector(this_PE)) ! Initialize base structure, ELL matrices and mathematic vectors. Locus_Name = 'Rows' call Initialize (Row_Structure, Row_Length_Vector, Locus_Name, status) Locus_Name = 'Columns' call Initialize (Column_Structure, Row_Length_Vector, Locus_Name, status) ELLM_Name = 'Coefficients' call Initialize (A_ELLM, MaxNonzeros, Row_Structure, Column_Structure, & ELLM_Name, status) call Initialize (B_ELLM, MaxNonzeros, Row_Structure, Column_Structure, & ELLM_Name, status) MV_Name = 'Variables' call Initialize (X_MV, Column_Structure, MV_Name, status) MV_Name = 'Equations' call Initialize (B_MV, Row_Structure, MV_Name, status) NRows = Length_Total(Row_Structure) ! Testing statements. ! Note that there can be no procedure calls inside a loop which ! is executed a different number of times on each PE, because ! global communication is done for verifications within a procedure. shift = - First_PE(Row_Structure) + 1 first_plus_last_PE_RS = Last_PE(Row_Structure) + First_PE(Row_Structure) do i = First_PE(Row_Structure), Last_PE(Row_Structure) ! Values(i,:) = global i Values(i + shift,:) = changetype(real, i) / MaxNonzeros ! Rows(i) = global i, but reversed in order on each PE Rows(i + shift) = first_plus_last_PE_RS - i ! Columns(i,:) = max((global i)-4,1) + (0,1,2,3,4) do j = 1, MaxNonzeros Columns(i + shift,j) = MAX(i-4,1) + j-1 end do end do VERIFY(Max_Nonzeros(A_ELLM)==MaxNonzeros,2) ! Set A_ELLM all at once: ! ! 1 PE: A_ELLM = [ 1 ] ! >1 PEs: A_ELLM = [ 0.2 0.2 0.2 0.2 0.2 ] ! [ 0.4 0.4 0.4 0.4 0.4 ] ! [ 0.6 0.6 0.6 0.6 0.6 ] ! [ 0.8 0.8 0.8 0.8 0.8 ] ! [ 1.0 1.0 1.0 1.0 1.0 ] ! [ 1.2 1.2 1.2 1.2 1.2 ] ! [ 1.4 1.4 1.4 1.4 1.4 ] ! [ 1.6 1.6 1.6 1.6 1.6 ] ! [ 1.8 1.8 1.8 1.8 1.8 ] ! [ 2.0 2.0 2.0 2.0 2.0 ] ! and matrix N = sum(i**2, i = 1, NPEs) call Set_Values (A_ELLM, Values, Columns) ! Set B_ELLM via 'partial replacement' call (even though we are ! replacing the whole thing) with half of Values, then use the ! Add_Values procedure to add the other half. ! Note that B_ELLM values are in reverse order on each PE. Values = Values/2.d0 call Set_Values (B_ELLM, Values, Rows, Columns) call Add_Values (B_ELLM, Values, Rows, Columns) ! Output the ELLMs. call Output (A_ELLM, MAX(1, NRows/10), MIN(NRows, NRows/10+50)) call Output (B_ELLM, MAX(1, NRows/10), MIN(NRows, NRows/10+50)) ! MatVec test. X_BNV = one ! Stuff X with 1's. X_MV = X_BNV call MatVec (A_ELLM, X_MV, B_MV) call Output (B_MV, MAX(1, NRows/10), MIN(NRows, NRows/10+50)) MaxB = Maximum(B_MV) MinB = Minimum(B_MV) AvgB = Average(B_MV) if (.not. VeryClose(MinB, one) ) then if (this_is_IO_PE) then write (6,*) 'Error in Minimum B => ', MinB end if end if if (.not. VeryClose(MaxB, changetype(real,NRows)) ) then if (this_is_IO_PE) then write (6,*) 'Error in Maximum B => ', MaxB end if end if if (.not. VeryClose(AvgB, (MaxB+MinB)*half) ) then if (this_is_IO_PE) then write (6,*) 'Error in Average B => ', AvgB end if end if ! This should use already-communicated values to get the same answer. call MatVec (A_ELLM, X_MV, B_MV) call Output (B_MV, MAX(1, NRows/10), MIN(NRows, NRows/10+50)) ! Norm test for resultant of MatVec (which should be {1,2,3,4,...}). ! This makes use of the fact that ! ! -- ! \ 2 1 3 2 ! / k = - (2 n + 3 n + n) ! -- 6 ! k=1,n B_Norm2 = Two_Norm(B_MV) NRows_real = changetype(real,NRows) if (this_is_IO_PE) then write (6,100) 'Norm test:' write (6,100) ' ||B||_2 = ', B_Norm2 100 format (/,a,f15.1) if (.not. VeryClose(B_Norm2**2, & (two * NRows_real**3 + three * NRows_real**2 + NRows_real)/six)) then write (6,*) 'Error -- ||B||_2 is incorrect.' end if end if ! This MatVec should require new communication. X_BNV = ten ! Stuff X with 10's. X_MV = X_BNV call MatVec (A_ELLM, X_MV, B_MV) call Output (B_MV, MAX(1, NRows/10), MIN(NRows, NRows/10+50)) if (.not. VeryClose(Average(B_MV), AvgB*ten) ) then if (this_is_IO_PE) then write (6,*) 'Error -- Two consecutive MatVecs give incorrect answers.' end if end if ! Check some things that are known: if (.not. VeryClose(Average(A_ELLM), & changetype(real,half*(NRows+1)/NRows)) ) then if (this_is_IO_PE) then write (6,*) 'Error -- Average is incorrect.' end if end if if (.not. Sum(A_ELLM) >= One_Norm(A_ELLM)) then if (this_is_IO_PE) then write (6,*) 'Error -- Sum or One_Norm is incorrect.' end if end if if (.not. Sum(A_ELLM) >= Infinity_Norm(A_ELLM)) then if (this_is_IO_PE) then write (6,*) 'Error -- Sum or Infinity_Norm is incorrect.' end if end if if (.not. VeryClose(Minimum(A_ELLM), & one/changetype(real,Max_Nonzeros(A_ELLM)))) then if (this_is_IO_PE) then write (6,*) 'Error -- Minimum is incorrect.' end if end if ! Tweak one value of A_ELLM on each PE and re-output. call Set_Values (A_ELLM, 10.d0, Last_PE(Row_Structure), & Last_PE(Row_Structure)) call Output (A_ELLM, MAX(1, NRows/10), MIN(NRows, NRows/10+50)) ! Check state of the ELL matrices. VERIFY(Valid_State(A_ELLM),0) VERIFY(Valid_State(B_ELLM),0) ! Test the Harwell-Boeing reader. call Finalize (X_MV) ! Note: must finalize X_MV before A_ELLM because ! the MatVec with A_ELLM created an OV in X_MV ! based on the Data_Index in A_ELLM. call Finalize (B_MV) call Finalize (A_ELLM) call Finalize (B_ELLM) call Finalize (Row_Structure) call Finalize (Column_Structure) if (this_is_IO_PE) then open (unit=8, & File='source/class/linear_algebra/battery/Augustus_Prob0_MH_K2_8x8x8.hb') end if call Read_Harwell_Boeing (A_ELLM, RHS_MV=B_MV, Solution_MV=X_MV, & Row_Structure=Row_Structure, & Column_Structure=Column_Structure, Unit=8, & status=status) call Output (A_ELLM, MAX(1, NRows/10), MIN(NRows, NRows/10+50)) call Output (X_MV, MAX(1, NRows/10), MIN(NRows, NRows/10+50)) call Output (B_MV, MAX(1, NRows/10), MIN(NRows, NRows/10+50)) ! Test Residual and MatVec. call Initialize (Residual_MV, Row_Structure, 'Residual', status) call Residual (Residual_MV, A_ELLM, X_MV, B_MV) ResidualNorm1 = Norm(Residual_MV) call MatVec (A_ELLM, X_MV, B_MV) if (this_is_IO_PE) then write (6,101) 'The next mathematic vector should be the same as', & 'the previous one, except for roundoff.' 101 format (/,a,/,a) end if call Output (B_MV, MAX(1, NRows/10), MIN(NRows, NRows/10+50)) call Residual (Residual_MV, A_ELLM, X_MV, B_MV) ResidualNorm2 = Norm(Residual_MV) if (this_is_IO_PE) then ! Correct value for ResidualNorm1 is: ! 8.145846809344343E-13 on Intel/Absoft ! 8.145895568345390E-13 on Intel/Lahey if (ResidualNorm1 < 8.14d-13 .or. & ResidualNorm1 > 8.15d-13) then write (6,*) 'Residual Norm 1 out of bounds: ', ResidualNorm1 end if if (.not. VeryClose(ResidualNorm2,zero)) then write (6,*) 'Error: Residual Norm 2 is nonzero: ', ResidualNorm2 end if end if ! Also need ! 1: call Add (ELLM1, ELLM2, ELLM3) or call Add_to_ELLM (ELLM1, ELLM2) ! 2: ELLM1 = ELLM2 ! 3: call Scale (ELLM, scalar) ! 4: ELLM1 == ELLM2 ! Check state of the ELL matrices. VERIFY(Valid_State(A_ELLM),0) ! Finalize objects and communications. call Finalize (X_MV) ! Note: must finalize X_MV before A_ELLM because ! the MatVec with A_ELLM created an OV in X_MV ! based on the Data_Index in A_ELLM. call Finalize (A_ELLM) call Finalize (Rows) call Finalize (Values) call Finalize (Columns) call Finalize (X_BNV) call Finalize (B_MV) call Finalize (Row_Structure) call Finalize (Column_Structure) call Finalize (Comm) end