From 3e9a5c0c5b41ef4c14f29c99e7fd7721d1ed3e4a Mon Sep 17 00:00:00 2001 From: Cirdans-Home Date: Fri, 4 Oct 2024 12:28:36 +0000 Subject: [PATCH 01/27] Remove diagonal zeros from aggregation --- amgprec/impl/aggregator/amg_c_soc1_map_bld.F90 | 5 ++--- amgprec/impl/aggregator/amg_d_soc1_map_bld.F90 | 5 ++--- amgprec/impl/aggregator/amg_s_soc1_map_bld.F90 | 5 ++--- amgprec/impl/aggregator/amg_z_soc1_map_bld.F90 | 5 ++--- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/amgprec/impl/aggregator/amg_c_soc1_map_bld.F90 b/amgprec/impl/aggregator/amg_c_soc1_map_bld.F90 index 24720675..36c4311c 100644 --- a/amgprec/impl/aggregator/amg_c_soc1_map_bld.F90 +++ b/amgprec/impl/aggregator/amg_c_soc1_map_bld.F90 @@ -250,7 +250,7 @@ subroutine amg_c_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in ! we will not reset. if (j>nr) cycle step1 if (ilaggr(j) > 0) cycle step1 - if (abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))) then + if ((abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))).and.(diag(i).ne.czero)) then ip = ip + 1 icol(ip) = icol(k) end if @@ -357,7 +357,7 @@ subroutine amg_c_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in do k=1, nz j = icol(k) if ((1<=j).and.(j<=nr)) then - if (abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))) then + if ((abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))).and.(diag(i).ne.czero)) then ip = ip + 1 icol(ip) = icol(k) end if @@ -545,4 +545,3 @@ subroutine amg_c_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in return end subroutine amg_c_soc1_map_bld - diff --git a/amgprec/impl/aggregator/amg_d_soc1_map_bld.F90 b/amgprec/impl/aggregator/amg_d_soc1_map_bld.F90 index 200d630c..b38344ed 100644 --- a/amgprec/impl/aggregator/amg_d_soc1_map_bld.F90 +++ b/amgprec/impl/aggregator/amg_d_soc1_map_bld.F90 @@ -250,7 +250,7 @@ subroutine amg_d_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in ! we will not reset. if (j>nr) cycle step1 if (ilaggr(j) > 0) cycle step1 - if (abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))) then + if ((abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))).and.(diag(i).ne.dzero)) then ip = ip + 1 icol(ip) = icol(k) end if @@ -357,7 +357,7 @@ subroutine amg_d_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in do k=1, nz j = icol(k) if ((1<=j).and.(j<=nr)) then - if (abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))) then + if ((abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))).and.(diag(i).ne.dzero)) then ip = ip + 1 icol(ip) = icol(k) end if @@ -545,4 +545,3 @@ subroutine amg_d_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in return end subroutine amg_d_soc1_map_bld - diff --git a/amgprec/impl/aggregator/amg_s_soc1_map_bld.F90 b/amgprec/impl/aggregator/amg_s_soc1_map_bld.F90 index 0f8bb7dd..d5331992 100644 --- a/amgprec/impl/aggregator/amg_s_soc1_map_bld.F90 +++ b/amgprec/impl/aggregator/amg_s_soc1_map_bld.F90 @@ -250,7 +250,7 @@ subroutine amg_s_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in ! we will not reset. if (j>nr) cycle step1 if (ilaggr(j) > 0) cycle step1 - if (abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))) then + if ((abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))).and.(diag(i).ne.szero)) then ip = ip + 1 icol(ip) = icol(k) end if @@ -357,7 +357,7 @@ subroutine amg_s_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in do k=1, nz j = icol(k) if ((1<=j).and.(j<=nr)) then - if (abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))) then + if ((abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))).and.(diag(i).ne.szero)) then ip = ip + 1 icol(ip) = icol(k) end if @@ -545,4 +545,3 @@ subroutine amg_s_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in return end subroutine amg_s_soc1_map_bld - diff --git a/amgprec/impl/aggregator/amg_z_soc1_map_bld.F90 b/amgprec/impl/aggregator/amg_z_soc1_map_bld.F90 index 7961921a..de5eb91c 100644 --- a/amgprec/impl/aggregator/amg_z_soc1_map_bld.F90 +++ b/amgprec/impl/aggregator/amg_z_soc1_map_bld.F90 @@ -250,7 +250,7 @@ subroutine amg_z_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in ! we will not reset. if (j>nr) cycle step1 if (ilaggr(j) > 0) cycle step1 - if (abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))) then + if ((abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))).and.(diag(i).ne.zzero)) then ip = ip + 1 icol(ip) = icol(k) end if @@ -357,7 +357,7 @@ subroutine amg_z_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in do k=1, nz j = icol(k) if ((1<=j).and.(j<=nr)) then - if (abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))) then + if ((abs(val(k)) > theta*sqrt(abs(diag(i)*diag(j)))).and.(diag(i).ne.zzero)) then ip = ip + 1 icol(ip) = icol(k) end if @@ -545,4 +545,3 @@ subroutine amg_z_soc1_map_bld(iorder,theta,clean_zeros,a,desc_a,nlaggr,ilaggr,in return end subroutine amg_z_soc1_map_bld - From 8966ecb4a6f7e9031c1a56a164a21ad810bbef03 Mon Sep 17 00:00:00 2001 From: Cirdans-Home Date: Wed, 9 Oct 2024 09:43:43 +0000 Subject: [PATCH 02/27] First implementation of l1-aggregation --- amgprec/amg_base_prec_type.F90 | 15 ++++--- amgprec/amg_c_inner_mod.f90 | 3 +- amgprec/amg_d_inner_mod.f90 | 3 +- amgprec/amg_d_parmatch_aggregator_mod.F90 | 6 ++- amgprec/amg_s_inner_mod.f90 | 3 +- amgprec/amg_s_parmatch_aggregator_mod.F90 | 6 ++- amgprec/amg_z_inner_mod.f90 | 3 +- .../amg_c_dec_aggregator_mat_bld.f90 | 17 ++++---- .../aggregator/amg_caggrmat_minnrg_bld.f90 | 13 +++++- .../aggregator/amg_caggrmat_nosmth_bld.f90 | 14 +++++-- .../impl/aggregator/amg_caggrmat_smth_bld.f90 | 40 ++++++++++++++++--- .../amg_d_dec_aggregator_mat_bld.f90 | 17 ++++---- .../amg_d_parmatch_aggregator_mat_bld.F90 | 17 ++++---- .../aggregator/amg_d_parmatch_smth_bld.F90 | 33 +++++++++++++-- .../aggregator/amg_d_parmatch_unsmth_bld.F90 | 12 +++++- .../aggregator/amg_daggrmat_minnrg_bld.f90 | 13 +++++- .../aggregator/amg_daggrmat_nosmth_bld.f90 | 14 +++++-- .../impl/aggregator/amg_daggrmat_smth_bld.f90 | 40 ++++++++++++++++--- .../amg_s_dec_aggregator_mat_bld.f90 | 17 ++++---- .../amg_s_parmatch_aggregator_mat_bld.F90 | 17 ++++---- .../aggregator/amg_s_parmatch_smth_bld.F90 | 33 +++++++++++++-- .../aggregator/amg_s_parmatch_unsmth_bld.F90 | 12 +++++- .../aggregator/amg_saggrmat_minnrg_bld.f90 | 13 +++++- .../aggregator/amg_saggrmat_nosmth_bld.f90 | 14 +++++-- .../impl/aggregator/amg_saggrmat_smth_bld.f90 | 40 ++++++++++++++++--- .../amg_z_dec_aggregator_mat_bld.f90 | 17 ++++---- .../aggregator/amg_zaggrmat_minnrg_bld.f90 | 13 +++++- .../aggregator/amg_zaggrmat_nosmth_bld.f90 | 14 +++++-- .../impl/aggregator/amg_zaggrmat_smth_bld.f90 | 40 ++++++++++++++++--- 29 files changed, 383 insertions(+), 116 deletions(-) diff --git a/amgprec/amg_base_prec_type.F90 b/amgprec/amg_base_prec_type.F90 index 896bf13b..d99ca566 100644 --- a/amgprec/amg_base_prec_type.F90 +++ b/amgprec/amg_base_prec_type.F90 @@ -288,11 +288,12 @@ module amg_base_prec_type ! ! Legal values for entry: amg_aggr_prol_ ! - integer(psb_ipk_), parameter :: amg_no_smooth_ = 0 - integer(psb_ipk_), parameter :: amg_smooth_prol_ = 1 - integer(psb_ipk_), parameter :: amg_min_energy_ = 2 + integer(psb_ipk_), parameter :: amg_no_smooth_ = 0 + integer(psb_ipk_), parameter :: amg_smooth_prol_ = 1 + integer(psb_ipk_), parameter :: amg_l1_smooth_prol_ = 2 + integer(psb_ipk_), parameter :: amg_min_energy_ = 3 ! Disabling min_energy for the time being. - integer(psb_ipk_), parameter :: amg_max_aggr_prol_=amg_smooth_prol_ + integer(psb_ipk_), parameter :: amg_max_aggr_prol_= amg_l1_smooth_prol_ ! ! Legal values for entry: amg_aggr_filter_ ! @@ -376,8 +377,8 @@ module amg_base_prec_type character(len=19), parameter, private :: & & eigen_estimates(0:0)=(/'infinity norm '/) character(len=15), parameter, private :: & - & aggr_prols(0:3)=(/'unsmoothed ','smoothed ',& - & 'min energy ','bizr. smoothed'/) + & aggr_prols(0:4)=(/'unsmoothed ','smoothed ',& + & 'l1-smoothed ','min energy ','bizr. smoothed'/) character(len=15), parameter, private :: & & aggr_filters(0:1)=(/'no filtering ','filtering '/) character(len=15), parameter, private :: & @@ -548,6 +549,8 @@ contains val = amg_no_smooth_ case('SMOOTHED') val = amg_smooth_prol_ + case('L1-SMOOTHED','L1SMOOTHED') + val = amg_l1_smooth_prol_ case('MINENERGY') val = amg_min_energy_ case('NOPREC') diff --git a/amgprec/amg_c_inner_mod.f90 b/amgprec/amg_c_inner_mod.f90 index ac260134..c97b8c3f 100644 --- a/amgprec/amg_c_inner_mod.f90 +++ b/amgprec/amg_c_inner_mod.f90 @@ -109,11 +109,12 @@ module amg_c_inner_mod end interface amg_map_to_tprol abstract interface - subroutine amg_caggrmat_var_bld(a,desc_a,ilaggr,nlaggr,parms,& + subroutine amg_caggrmat_var_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,parms,& & ac,desc_ac,op_prol,op_restr,t_prol,info) import :: psb_cspmat_type, psb_desc_type, psb_spk_, psb_ipk_, psb_lpk_, psb_lcspmat_type import :: amg_c_onelev_type, amg_sml_parms implicit none + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_cspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) diff --git a/amgprec/amg_d_inner_mod.f90 b/amgprec/amg_d_inner_mod.f90 index 8fa96609..83176af7 100644 --- a/amgprec/amg_d_inner_mod.f90 +++ b/amgprec/amg_d_inner_mod.f90 @@ -109,11 +109,12 @@ module amg_d_inner_mod end interface amg_map_to_tprol abstract interface - subroutine amg_daggrmat_var_bld(a,desc_a,ilaggr,nlaggr,parms,& + subroutine amg_daggrmat_var_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,parms,& & ac,desc_ac,op_prol,op_restr,t_prol,info) import :: psb_dspmat_type, psb_desc_type, psb_dpk_, psb_ipk_, psb_lpk_, psb_ldspmat_type import :: amg_d_onelev_type, amg_dml_parms implicit none + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_dspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) diff --git a/amgprec/amg_d_parmatch_aggregator_mod.F90 b/amgprec/amg_d_parmatch_aggregator_mod.F90 index 525bb0c3..def1fba1 100644 --- a/amgprec/amg_d_parmatch_aggregator_mod.F90 +++ b/amgprec/amg_d_parmatch_aggregator_mod.F90 @@ -244,11 +244,12 @@ module amg_d_parmatch_aggregator_mod end interface interface - subroutine amg_d_parmatch_unsmth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& + subroutine amg_d_parmatch_unsmth_bld(dol1smoothing,ag,a,desc_a,ilaggr,nlaggr,parms,& & ac,desc_ac,op_prol,op_restr,t_prol,info) import :: amg_d_parmatch_aggregator_type, psb_desc_type, psb_dspmat_type,& & psb_ldspmat_type, psb_dpk_, psb_ipk_, psb_lpk_, amg_dml_parms, amg_daggr_data implicit none + integer(psb_ipk_), intent(in) :: dol1smoothing class(amg_d_parmatch_aggregator_type), target, intent(inout) :: ag type(psb_dspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a @@ -262,11 +263,12 @@ module amg_d_parmatch_aggregator_mod end interface interface - subroutine amg_d_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& + subroutine amg_d_parmatch_smth_bld(dol1smoothing,ag,a,desc_a,ilaggr,nlaggr,parms,& & ac,desc_ac,op_prol,op_restr,t_prol,info) import :: amg_d_parmatch_aggregator_type, psb_desc_type, psb_dspmat_type,& & psb_ldspmat_type, psb_dpk_, psb_ipk_, psb_lpk_, amg_dml_parms, amg_daggr_data implicit none + integer(psb_ipk_), intent(in) :: dol1smoothing class(amg_d_parmatch_aggregator_type), target, intent(inout) :: ag type(psb_dspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a diff --git a/amgprec/amg_s_inner_mod.f90 b/amgprec/amg_s_inner_mod.f90 index 85ed1089..be883b21 100644 --- a/amgprec/amg_s_inner_mod.f90 +++ b/amgprec/amg_s_inner_mod.f90 @@ -109,11 +109,12 @@ module amg_s_inner_mod end interface amg_map_to_tprol abstract interface - subroutine amg_saggrmat_var_bld(a,desc_a,ilaggr,nlaggr,parms,& + subroutine amg_saggrmat_var_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,parms,& & ac,desc_ac,op_prol,op_restr,t_prol,info) import :: psb_sspmat_type, psb_desc_type, psb_spk_, psb_ipk_, psb_lpk_, psb_lsspmat_type import :: amg_s_onelev_type, amg_sml_parms implicit none + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_sspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) diff --git a/amgprec/amg_s_parmatch_aggregator_mod.F90 b/amgprec/amg_s_parmatch_aggregator_mod.F90 index d58bd750..059c5b73 100644 --- a/amgprec/amg_s_parmatch_aggregator_mod.F90 +++ b/amgprec/amg_s_parmatch_aggregator_mod.F90 @@ -244,11 +244,12 @@ module amg_s_parmatch_aggregator_mod end interface interface - subroutine amg_s_parmatch_unsmth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& + subroutine amg_s_parmatch_unsmth_bld(dol1smoothing,ag,a,desc_a,ilaggr,nlaggr,parms,& & ac,desc_ac,op_prol,op_restr,t_prol,info) import :: amg_s_parmatch_aggregator_type, psb_desc_type, psb_sspmat_type,& & psb_lsspmat_type, psb_dpk_, psb_ipk_, psb_lpk_, amg_sml_parms, amg_saggr_data implicit none + integer(psb_ipk_), intent(in) :: dol1smoothing class(amg_s_parmatch_aggregator_type), target, intent(inout) :: ag type(psb_sspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a @@ -262,11 +263,12 @@ module amg_s_parmatch_aggregator_mod end interface interface - subroutine amg_s_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& + subroutine amg_s_parmatch_smth_bld(dol1smoothing,ag,a,desc_a,ilaggr,nlaggr,parms,& & ac,desc_ac,op_prol,op_restr,t_prol,info) import :: amg_s_parmatch_aggregator_type, psb_desc_type, psb_sspmat_type,& & psb_lsspmat_type, psb_dpk_, psb_ipk_, psb_lpk_, amg_sml_parms, amg_saggr_data implicit none + integer(psb_ipk_), intent(in) :: dol1smoothing class(amg_s_parmatch_aggregator_type), target, intent(inout) :: ag type(psb_sspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a diff --git a/amgprec/amg_z_inner_mod.f90 b/amgprec/amg_z_inner_mod.f90 index bf997651..fb7139fd 100644 --- a/amgprec/amg_z_inner_mod.f90 +++ b/amgprec/amg_z_inner_mod.f90 @@ -109,11 +109,12 @@ module amg_z_inner_mod end interface amg_map_to_tprol abstract interface - subroutine amg_zaggrmat_var_bld(a,desc_a,ilaggr,nlaggr,parms,& + subroutine amg_zaggrmat_var_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,parms,& & ac,desc_ac,op_prol,op_restr,t_prol,info) import :: psb_zspmat_type, psb_desc_type, psb_dpk_, psb_ipk_, psb_lpk_, psb_lzspmat_type import :: amg_z_onelev_type, amg_dml_parms implicit none + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_zspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) diff --git a/amgprec/impl/aggregator/amg_c_dec_aggregator_mat_bld.f90 b/amgprec/impl/aggregator/amg_c_dec_aggregator_mat_bld.f90 index 2c9317d1..186e7a1e 100644 --- a/amgprec/impl/aggregator/amg_c_dec_aggregator_mat_bld.f90 +++ b/amgprec/impl/aggregator/amg_c_dec_aggregator_mat_bld.f90 @@ -177,23 +177,24 @@ subroutine amg_c_dec_aggregator_mat_bld(ag,parms,a,desc_a,ilaggr,nlaggr,& select case (parms%aggr_prol) case (amg_no_smooth_) - call amg_caggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,& - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_caggrmat_nosmth_bld(parms%aggr_prol,a,desc_a,ilaggr,& + nlaggr,parms,ac,desc_ac,op_prol,op_restr,t_prol,info) - case(amg_smooth_prol_) + case(amg_smooth_prol_,amg_l1_smooth_prol_) - call amg_caggrmat_smth_bld(a,desc_a,ilaggr,nlaggr, & - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_caggrmat_smth_bld(parms%aggr_prol,a,desc_a,& + ilaggr,nlaggr,parms,ac,desc_ac,op_prol,& + op_restr,t_prol,info) !!$ case(amg_biz_prol_) !!$ !!$ call amg_caggrmat_biz_bld(a,desc_a,ilaggr,nlaggr, & !!$ & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) - + case(amg_min_energy_) - call amg_caggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr, & - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_caggrmat_minnrg_bld(parms%aggr_prol,a,desc_a,ilaggr,& + nlaggr,parms,ac,desc_ac,op_prol,op_restr,t_prol,info) case default info = psb_err_internal_error_ diff --git a/amgprec/impl/aggregator/amg_caggrmat_minnrg_bld.f90 b/amgprec/impl/aggregator/amg_caggrmat_minnrg_bld.f90 index 8ac86dc6..3d223279 100644 --- a/amgprec/impl/aggregator/amg_caggrmat_minnrg_bld.f90 +++ b/amgprec/impl/aggregator/amg_caggrmat_minnrg_bld.f90 @@ -69,6 +69,7 @@ ! ! ! Arguments: +! dol1smoothing - fictitious integer argument, it is not used inside ! a - type(psb_cspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -104,8 +105,8 @@ ! Error code. ! ! -subroutine amg_caggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_caggrmat_minnrg_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_c_inner_mod, amg_protect_name => amg_caggrmat_minnrg_bld @@ -113,6 +114,7 @@ subroutine amg_caggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_cspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -171,6 +173,13 @@ subroutine amg_caggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& filter_mat = (parms%aggr_filter == amg_filter_mat_) + if (dol1smoothing.ne.amg_no_smooth_) then + info=psb_err_fatal_; + call psb_errpush(info,name,a_err='Are you trying to smooth an unsmoothed aggregation?') + goto 9999 + end if + + !NEEDS TO BE REWORKED !! ! naggr: number of local aggregates diff --git a/amgprec/impl/aggregator/amg_caggrmat_nosmth_bld.f90 b/amgprec/impl/aggregator/amg_caggrmat_nosmth_bld.f90 index 87c79dc6..9699545e 100644 --- a/amgprec/impl/aggregator/amg_caggrmat_nosmth_bld.f90 +++ b/amgprec/impl/aggregator/amg_caggrmat_nosmth_bld.f90 @@ -94,10 +94,11 @@ ! ! info - integer, output. ! Error code. +! dol1smoothing - optional, this is here just for interfacing reasons. It is not used by the +! code ! -! -subroutine amg_caggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_caggrmat_nosmth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_c_inner_mod, amg_protect_name => amg_caggrmat_nosmth_bld @@ -105,6 +106,7 @@ subroutine amg_caggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_cspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -137,6 +139,12 @@ subroutine amg_caggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& ctxt = desc_a%get_context() call psb_info(ctxt, me, np) + if (dol1smoothing.ne.amg_no_smooth_) then + info=psb_err_fatal_; + call psb_errpush(info,name,a_err='Are you trying to smooth an unsmoothed aggregation?') + goto 9999 + end if + nglob = desc_a%get_global_rows() nrow = desc_a%get_local_rows() ncol = desc_a%get_local_cols() diff --git a/amgprec/impl/aggregator/amg_caggrmat_smth_bld.f90 b/amgprec/impl/aggregator/amg_caggrmat_smth_bld.f90 index 67fce476..4cd75284 100644 --- a/amgprec/impl/aggregator/amg_caggrmat_smth_bld.f90 +++ b/amgprec/impl/aggregator/amg_caggrmat_smth_bld.f90 @@ -69,6 +69,8 @@ ! ! ! Arguments: +! dol1smooth - Integer taking the type of smoother that has to be used +! on the tentative prolongator ! a - type(psb_cspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -102,8 +104,8 @@ ! info - integer, output. ! Error code. ! -subroutine amg_caggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_caggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_c_inner_mod, amg_protect_name => amg_caggrmat_smth_bld @@ -112,6 +114,7 @@ subroutine amg_caggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_cspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -132,7 +135,7 @@ subroutine amg_caggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& type(psb_c_coo_sparse_mat) :: coo_prol, coo_restr type(psb_c_csr_sparse_mat) :: acsr1, acsrf, csr_prol, acsr complex(psb_spk_), allocatable :: adiag(:) - real(psb_spk_), allocatable :: arwsum(:) + real(psb_spk_), allocatable :: arwsum(:),l1rwsum(:) integer(psb_ipk_) :: ierr(5) logical :: filter_mat integer(psb_ipk_) :: debug_level, debug_unit, err_act @@ -141,6 +144,7 @@ subroutine amg_caggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& logical, parameter :: debug_new=.false. character(len=80) :: filename logical, parameter :: do_timings=.false. + logical :: do_l1correction=.false. integer(psb_ipk_), save :: idx_spspmm=-1, idx_phase1=-1, idx_gtrans=-1, idx_phase2=-1, idx_refine=-1 integer(psb_ipk_), save :: idx_phase3=-1, idx_cdasb=-1, idx_ptap=-1 @@ -173,6 +177,9 @@ subroutine amg_caggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if ((do_timings).and.(idx_ptap==-1)) & & idx_ptap = psb_get_timer_idx("DEC_SMTH_BLD: ptap_bld ") + ! check if we have to use Jacobi or l1-Jacobi to smooth the tentative prolongator + if (dol1smoothing.eq.amg_l1_smooth_prol_) do_l1correction=.true. + nglob = desc_a%get_global_rows() nrow = desc_a%get_local_rows() @@ -200,6 +207,24 @@ subroutine amg_caggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if (info == psb_success_) & & call psb_halo(adiag,desc_a,info) if (info == psb_success_) call a%cp_to(acsr) + ! + ! Do the l1-correction on the diagonal if it is requested + ! + if (do_l1correction) then + allocate(l1rwsum(nrow)) + call acsr%arwsum(l1rwsum) + if (info == psb_success_) & + & call psb_realloc(ncol,l1rwsum,info) + if (info == psb_success_) & + & call psb_halo(l1rwsum,desc_a,info) + ! \tilde{D}_{i,i} = \sum_{j \ne i} |a_{i,j}| + !$OMP parallel do private(i) schedule(static) + do i=1,size(adiag) + adiag(i) = adiag(i) + l1rwsum(i) - abs(adiag(i)) + end do + !$OMP end parallel do + end if + if(info /= psb_success_) then call psb_errpush(psb_err_from_subroutine_,name,a_err='sp_getdiag') @@ -230,7 +255,7 @@ subroutine amg_caggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& enddo if (jd == -1) then - write(0,*) name,': Warning: there is no diagonal element', i + if (.not.do_l1correction) write(0,*) 'Wrong input: we need the diagonal!!!!', i else acsrf%val(jd)=acsrf%val(jd)-tmp end if @@ -252,14 +277,16 @@ subroutine amg_caggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& !$OMP end parallel do if (parms%aggr_omega_alg == amg_eig_est_) then - if (parms%aggr_eig == amg_max_norm_) then + if (do_l1correction) then + ! For l1-Jacobi this can be estimated with 1 + parms%aggr_omega_val = done + else if (parms%aggr_eig == amg_max_norm_) then allocate(arwsum(nrow)) call acsr%arwsum(arwsum) anorm = maxval(abs(adiag(1:nrow)*arwsum(1:nrow))) call psb_amx(ctxt,anorm) omega = 4.d0/(3.d0*anorm) parms%aggr_omega_val = omega - else info = psb_err_internal_error_ call psb_errpush(info,name,a_err='invalid amg_aggr_eig_') @@ -322,6 +349,7 @@ subroutine amg_caggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if (debug_level >= psb_debug_outer_) & & write(debug_unit,*) me,' ',trim(name),& & 'Done smooth_aggregate ' + if (allocated(l1rwsum)) deallocate(l1rwsum) call psb_erractionrestore(err_act) return diff --git a/amgprec/impl/aggregator/amg_d_dec_aggregator_mat_bld.f90 b/amgprec/impl/aggregator/amg_d_dec_aggregator_mat_bld.f90 index 7b01a0b8..65bd08e8 100644 --- a/amgprec/impl/aggregator/amg_d_dec_aggregator_mat_bld.f90 +++ b/amgprec/impl/aggregator/amg_d_dec_aggregator_mat_bld.f90 @@ -177,23 +177,24 @@ subroutine amg_d_dec_aggregator_mat_bld(ag,parms,a,desc_a,ilaggr,nlaggr,& select case (parms%aggr_prol) case (amg_no_smooth_) - call amg_daggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,& - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_daggrmat_nosmth_bld(parms%aggr_prol,a,desc_a,ilaggr,& + nlaggr,parms,ac,desc_ac,op_prol,op_restr,t_prol,info) - case(amg_smooth_prol_) + case(amg_smooth_prol_,amg_l1_smooth_prol_) - call amg_daggrmat_smth_bld(a,desc_a,ilaggr,nlaggr, & - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_daggrmat_smth_bld(parms%aggr_prol,a,desc_a,& + ilaggr,nlaggr,parms,ac,desc_ac,op_prol,& + op_restr,t_prol,info) !!$ case(amg_biz_prol_) !!$ !!$ call amg_daggrmat_biz_bld(a,desc_a,ilaggr,nlaggr, & !!$ & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) - + case(amg_min_energy_) - call amg_daggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr, & - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_daggrmat_minnrg_bld(parms%aggr_prol,a,desc_a,ilaggr,& + nlaggr,parms,ac,desc_ac,op_prol,op_restr,t_prol,info) case default info = psb_err_internal_error_ diff --git a/amgprec/impl/aggregator/amg_d_parmatch_aggregator_mat_bld.F90 b/amgprec/impl/aggregator/amg_d_parmatch_aggregator_mat_bld.F90 index 9b1171e0..1766d4a4 100644 --- a/amgprec/impl/aggregator/amg_d_parmatch_aggregator_mat_bld.F90 +++ b/amgprec/impl/aggregator/amg_d_parmatch_aggregator_mat_bld.F90 @@ -184,20 +184,23 @@ subroutine amg_d_parmatch_aggregator_mat_bld(ag,parms,a,desc_a,ilaggr,nlaggr,& ! select case (parms%aggr_prol) case (amg_no_smooth_) - call amg_d_parmatch_unsmth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_d_parmatch_unsmth_bld(parms%aggr_prol,ag,a,desc_a,& + ilaggr,nlaggr,parms,ac,desc_ac,op_prol,op_restr,& + t_prol,info) - case(amg_smooth_prol_) - call amg_d_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) + case(amg_smooth_prol_,amg_l1_smooth_prol_) + call amg_d_parmatch_smth_bld(parms%aggr_prol,ag,a,desc_a,& + ilaggr,nlaggr,parms,ac,desc_ac,op_prol,op_restr,& + t_prol,info) !!$ case(amg_biz_prol_) !!$ call amg_daggrmat_biz_bld(a,desc_a,ilaggr,nlaggr, & !!$ & parms,ac,desc_ac,op_prol,op_restr,info) case(amg_min_energy_) - call amg_daggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr, & - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_daggrmat_minnrg_bld(parms%aggr_prol,a,desc_a,& + ilaggr,nlaggr,parms,ac,desc_ac,op_prol,op_restr,& + t_prol,info) case default info = psb_err_internal_error_ diff --git a/amgprec/impl/aggregator/amg_d_parmatch_smth_bld.F90 b/amgprec/impl/aggregator/amg_d_parmatch_smth_bld.F90 index b20b2fa8..23cd1459 100644 --- a/amgprec/impl/aggregator/amg_d_parmatch_smth_bld.F90 +++ b/amgprec/impl/aggregator/amg_d_parmatch_smth_bld.F90 @@ -69,6 +69,8 @@ ! ! ! Arguments: +! dol1smoothing - Select between l1-Jacobi and Jacobi as smoother for the +! tentative prolongator ! a - type(psb_dspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -102,8 +104,8 @@ ! info - integer, output. ! Error code. ! -subroutine amg_d_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_d_parmatch_smth_bld(dol1smoothing,ag,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_d_inner_mod @@ -116,6 +118,7 @@ subroutine amg_d_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing class(amg_d_parmatch_aggregator_type), target, intent(inout) :: ag type(psb_dspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a @@ -137,7 +140,7 @@ subroutine amg_d_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& type(psb_d_coo_sparse_mat) :: coo_prol, coo_restr type(psb_d_csr_sparse_mat) :: acsrf, csr_prol, acsr, tcsr real(psb_dpk_), allocatable :: adiag(:) - real(psb_dpk_), allocatable :: arwsum(:) + real(psb_dpk_), allocatable :: arwsum(:),l1rwsum(:) logical :: filter_mat integer(psb_ipk_) :: debug_level, debug_unit, err_act integer(psb_ipk_), parameter :: ncmax=16 @@ -145,6 +148,7 @@ subroutine amg_d_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& logical, parameter :: debug_new=.false., dump_r=.false., dump_p=.false., debug=.false. character(len=80) :: filename logical, parameter :: do_timings=.false. + logical :: do_l1correction=.false. integer(psb_ipk_), save :: idx_spspmm=-1, idx_phase1=-1, idx_gtrans=-1, idx_phase2=-1, idx_refine=-1, idx_phase3=-1 integer(psb_ipk_), save :: idx_cdasb=-1, idx_ptap=-1 @@ -166,6 +170,10 @@ subroutine amg_d_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& ncol = desc_a%get_local_cols() theta = parms%aggr_thresh + ! Check if we have to perform l1-Jacobi or Jacobi as smoother + if(dol1smoothing.eq.amg_l1_smooth_prol_) do_l1correction=.true. + + !write(0,*) me,' ',trim(name),' Start ',idx_spspmm if ((do_timings).and.(idx_spspmm==-1)) & & idx_spspmm = psb_get_timer_idx("PMC_SMTH_BLD: par_spspmm") @@ -217,6 +225,19 @@ subroutine amg_d_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& if (info == psb_success_) & & call psb_halo(adiag,desc_a,info) if (info == psb_success_) call a%cp_to(acsr) + ! Get the l1-diagonal of D + if (do_l1correction) then + allocate(l1rwsum(nrow)) + call acsr%arwsum(l1rwsum) + if (info == psb_success_) & + & call psb_realloc(ncol,l1rwsum,info) + if (info == psb_success_) & + & call psb_halo(l1rwsum,desc_a,info) + ! \tilde{D}_{i,i} = \sum_{j \ne i} |a_{i,j}| + do i=1,size(adiag) + adiag(i) = adiag(i) + l1rwsum(i) - abs(adiag(i)) + end do + end if if(info /= psb_success_) then call psb_errpush(psb_err_from_subroutine_,name,a_err='sp_getdiag') @@ -267,7 +288,10 @@ subroutine amg_d_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& if (parms%aggr_omega_alg == amg_eig_est_) then - if (parms%aggr_eig == amg_max_norm_) then + if (do_l1correction) then + ! For l1-Jacobi this can be estimated with 1 + parms%aggr_omega_val = done + else if (parms%aggr_eig == amg_max_norm_) then allocate(arwsum(nrow)) call acsr%arwsum(arwsum) anorm = maxval(abs(adiag(1:nrow)*arwsum(1:nrow))) @@ -373,6 +397,7 @@ subroutine amg_d_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& end block end if + if (allocated(l1rwsum)) deallocate(l1rwsum) if (do_timings) call psb_toc(idx_phase2) if (debug_level >= psb_debug_outer_) & diff --git a/amgprec/impl/aggregator/amg_d_parmatch_unsmth_bld.F90 b/amgprec/impl/aggregator/amg_d_parmatch_unsmth_bld.F90 index dc6574a0..85f1ec28 100644 --- a/amgprec/impl/aggregator/amg_d_parmatch_unsmth_bld.F90 +++ b/amgprec/impl/aggregator/amg_d_parmatch_unsmth_bld.F90 @@ -68,6 +68,8 @@ ! ! ! Arguments: +! dol1smoothing - this not actually used inside unsmoothed aggregation, it +! is used just to perform a check ! a - type(psb_dspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -101,8 +103,8 @@ ! info - integer, output. ! Error code. ! -subroutine amg_d_parmatch_unsmth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_d_parmatch_unsmth_bld(dol1smoothing,ag,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_d_inner_mod @@ -115,6 +117,7 @@ subroutine amg_d_parmatch_unsmth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing class(amg_d_parmatch_aggregator_type), target, intent(inout) :: ag type(psb_dspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a @@ -159,6 +162,11 @@ subroutine amg_d_parmatch_unsmth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& ictxt = desc_a%get_context() call psb_info(ictxt, me, np) + if (dol1smoothing.ne.amg_no_smooth_) then + info=psb_err_fatal_; + call psb_errpush(info,name,a_err='Are you trying to smooth an unsmoothed aggregation?') + goto 9999 + end if #if !defined(SERIAL_MPI) nglob = desc_a%get_global_rows() diff --git a/amgprec/impl/aggregator/amg_daggrmat_minnrg_bld.f90 b/amgprec/impl/aggregator/amg_daggrmat_minnrg_bld.f90 index 510339e7..c9f87f72 100644 --- a/amgprec/impl/aggregator/amg_daggrmat_minnrg_bld.f90 +++ b/amgprec/impl/aggregator/amg_daggrmat_minnrg_bld.f90 @@ -69,6 +69,7 @@ ! ! ! Arguments: +! dol1smoothing - fictitious integer argument, it is not used inside ! a - type(psb_dspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -104,8 +105,8 @@ ! Error code. ! ! -subroutine amg_daggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_daggrmat_minnrg_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_d_inner_mod, amg_protect_name => amg_daggrmat_minnrg_bld @@ -113,6 +114,7 @@ subroutine amg_daggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_dspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -171,6 +173,13 @@ subroutine amg_daggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& filter_mat = (parms%aggr_filter == amg_filter_mat_) + if (dol1smoothing.ne.amg_no_smooth_) then + info=psb_err_fatal_; + call psb_errpush(info,name,a_err='Are you trying to smooth an unsmoothed aggregation?') + goto 9999 + end if + + !NEEDS TO BE REWORKED !! ! naggr: number of local aggregates diff --git a/amgprec/impl/aggregator/amg_daggrmat_nosmth_bld.f90 b/amgprec/impl/aggregator/amg_daggrmat_nosmth_bld.f90 index 78e396cc..345316b1 100644 --- a/amgprec/impl/aggregator/amg_daggrmat_nosmth_bld.f90 +++ b/amgprec/impl/aggregator/amg_daggrmat_nosmth_bld.f90 @@ -94,10 +94,11 @@ ! ! info - integer, output. ! Error code. +! dol1smoothing - optional, this is here just for interfacing reasons. It is not used by the +! code ! -! -subroutine amg_daggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_daggrmat_nosmth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_d_inner_mod, amg_protect_name => amg_daggrmat_nosmth_bld @@ -105,6 +106,7 @@ subroutine amg_daggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_dspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -137,6 +139,12 @@ subroutine amg_daggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& ctxt = desc_a%get_context() call psb_info(ctxt, me, np) + if (dol1smoothing.ne.amg_no_smooth_) then + info=psb_err_fatal_; + call psb_errpush(info,name,a_err='Are you trying to smooth an unsmoothed aggregation?') + goto 9999 + end if + nglob = desc_a%get_global_rows() nrow = desc_a%get_local_rows() ncol = desc_a%get_local_cols() diff --git a/amgprec/impl/aggregator/amg_daggrmat_smth_bld.f90 b/amgprec/impl/aggregator/amg_daggrmat_smth_bld.f90 index d12f9c6b..399e27b6 100644 --- a/amgprec/impl/aggregator/amg_daggrmat_smth_bld.f90 +++ b/amgprec/impl/aggregator/amg_daggrmat_smth_bld.f90 @@ -69,6 +69,8 @@ ! ! ! Arguments: +! dol1smooth - Integer taking the type of smoother that has to be used +! on the tentative prolongator ! a - type(psb_dspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -102,8 +104,8 @@ ! info - integer, output. ! Error code. ! -subroutine amg_daggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_daggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_d_inner_mod, amg_protect_name => amg_daggrmat_smth_bld @@ -112,6 +114,7 @@ subroutine amg_daggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_dspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -132,7 +135,7 @@ subroutine amg_daggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& type(psb_d_coo_sparse_mat) :: coo_prol, coo_restr type(psb_d_csr_sparse_mat) :: acsr1, acsrf, csr_prol, acsr real(psb_dpk_), allocatable :: adiag(:) - real(psb_dpk_), allocatable :: arwsum(:) + real(psb_dpk_), allocatable :: arwsum(:),l1rwsum(:) integer(psb_ipk_) :: ierr(5) logical :: filter_mat integer(psb_ipk_) :: debug_level, debug_unit, err_act @@ -141,6 +144,7 @@ subroutine amg_daggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& logical, parameter :: debug_new=.false. character(len=80) :: filename logical, parameter :: do_timings=.false. + logical :: do_l1correction=.false. integer(psb_ipk_), save :: idx_spspmm=-1, idx_phase1=-1, idx_gtrans=-1, idx_phase2=-1, idx_refine=-1 integer(psb_ipk_), save :: idx_phase3=-1, idx_cdasb=-1, idx_ptap=-1 @@ -173,6 +177,9 @@ subroutine amg_daggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if ((do_timings).and.(idx_ptap==-1)) & & idx_ptap = psb_get_timer_idx("DEC_SMTH_BLD: ptap_bld ") + ! check if we have to use Jacobi or l1-Jacobi to smooth the tentative prolongator + if (dol1smoothing.eq.amg_l1_smooth_prol_) do_l1correction=.true. + nglob = desc_a%get_global_rows() nrow = desc_a%get_local_rows() @@ -200,6 +207,24 @@ subroutine amg_daggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if (info == psb_success_) & & call psb_halo(adiag,desc_a,info) if (info == psb_success_) call a%cp_to(acsr) + ! + ! Do the l1-correction on the diagonal if it is requested + ! + if (do_l1correction) then + allocate(l1rwsum(nrow)) + call acsr%arwsum(l1rwsum) + if (info == psb_success_) & + & call psb_realloc(ncol,l1rwsum,info) + if (info == psb_success_) & + & call psb_halo(l1rwsum,desc_a,info) + ! \tilde{D}_{i,i} = \sum_{j \ne i} |a_{i,j}| + !$OMP parallel do private(i) schedule(static) + do i=1,size(adiag) + adiag(i) = adiag(i) + l1rwsum(i) - abs(adiag(i)) + end do + !$OMP end parallel do + end if + if(info /= psb_success_) then call psb_errpush(psb_err_from_subroutine_,name,a_err='sp_getdiag') @@ -230,7 +255,7 @@ subroutine amg_daggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& enddo if (jd == -1) then - write(0,*) name,': Warning: there is no diagonal element', i + if (.not.do_l1correction) write(0,*) 'Wrong input: we need the diagonal!!!!', i else acsrf%val(jd)=acsrf%val(jd)-tmp end if @@ -252,14 +277,16 @@ subroutine amg_daggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& !$OMP end parallel do if (parms%aggr_omega_alg == amg_eig_est_) then - if (parms%aggr_eig == amg_max_norm_) then + if (do_l1correction) then + ! For l1-Jacobi this can be estimated with 1 + parms%aggr_omega_val = done + else if (parms%aggr_eig == amg_max_norm_) then allocate(arwsum(nrow)) call acsr%arwsum(arwsum) anorm = maxval(abs(adiag(1:nrow)*arwsum(1:nrow))) call psb_amx(ctxt,anorm) omega = 4.d0/(3.d0*anorm) parms%aggr_omega_val = omega - else info = psb_err_internal_error_ call psb_errpush(info,name,a_err='invalid amg_aggr_eig_') @@ -322,6 +349,7 @@ subroutine amg_daggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if (debug_level >= psb_debug_outer_) & & write(debug_unit,*) me,' ',trim(name),& & 'Done smooth_aggregate ' + if (allocated(l1rwsum)) deallocate(l1rwsum) call psb_erractionrestore(err_act) return diff --git a/amgprec/impl/aggregator/amg_s_dec_aggregator_mat_bld.f90 b/amgprec/impl/aggregator/amg_s_dec_aggregator_mat_bld.f90 index 39e96ec7..750889de 100644 --- a/amgprec/impl/aggregator/amg_s_dec_aggregator_mat_bld.f90 +++ b/amgprec/impl/aggregator/amg_s_dec_aggregator_mat_bld.f90 @@ -177,23 +177,24 @@ subroutine amg_s_dec_aggregator_mat_bld(ag,parms,a,desc_a,ilaggr,nlaggr,& select case (parms%aggr_prol) case (amg_no_smooth_) - call amg_saggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,& - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_saggrmat_nosmth_bld(parms%aggr_prol,a,desc_a,ilaggr,& + nlaggr,parms,ac,desc_ac,op_prol,op_restr,t_prol,info) - case(amg_smooth_prol_) + case(amg_smooth_prol_,amg_l1_smooth_prol_) - call amg_saggrmat_smth_bld(a,desc_a,ilaggr,nlaggr, & - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_saggrmat_smth_bld(parms%aggr_prol,a,desc_a,& + ilaggr,nlaggr,parms,ac,desc_ac,op_prol,& + op_restr,t_prol,info) !!$ case(amg_biz_prol_) !!$ !!$ call amg_saggrmat_biz_bld(a,desc_a,ilaggr,nlaggr, & !!$ & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) - + case(amg_min_energy_) - call amg_saggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr, & - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_saggrmat_minnrg_bld(parms%aggr_prol,a,desc_a,ilaggr,& + nlaggr,parms,ac,desc_ac,op_prol,op_restr,t_prol,info) case default info = psb_err_internal_error_ diff --git a/amgprec/impl/aggregator/amg_s_parmatch_aggregator_mat_bld.F90 b/amgprec/impl/aggregator/amg_s_parmatch_aggregator_mat_bld.F90 index 8c10d006..38dff13c 100644 --- a/amgprec/impl/aggregator/amg_s_parmatch_aggregator_mat_bld.F90 +++ b/amgprec/impl/aggregator/amg_s_parmatch_aggregator_mat_bld.F90 @@ -184,20 +184,23 @@ subroutine amg_s_parmatch_aggregator_mat_bld(ag,parms,a,desc_a,ilaggr,nlaggr,& ! select case (parms%aggr_prol) case (amg_no_smooth_) - call amg_s_parmatch_unsmth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_s_parmatch_unsmth_bld(parms%aggr_prol,ag,a,desc_a,& + ilaggr,nlaggr,parms,ac,desc_ac,op_prol,op_restr,& + t_prol,info) - case(amg_smooth_prol_) - call amg_s_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) + case(amg_smooth_prol_,amg_l1_smooth_prol_) + call amg_s_parmatch_smth_bld(parms%aggr_prol,ag,a,desc_a,& + ilaggr,nlaggr,parms,ac,desc_ac,op_prol,op_restr,& + t_prol,info) !!$ case(amg_biz_prol_) !!$ call amg_saggrmat_biz_bld(a,desc_a,ilaggr,nlaggr, & !!$ & parms,ac,desc_ac,op_prol,op_restr,info) case(amg_min_energy_) - call amg_saggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr, & - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_saggrmat_minnrg_bld(parms%aggr_prol,a,desc_a,& + ilaggr,nlaggr,parms,ac,desc_ac,op_prol,op_restr,& + t_prol,info) case default info = psb_err_internal_error_ diff --git a/amgprec/impl/aggregator/amg_s_parmatch_smth_bld.F90 b/amgprec/impl/aggregator/amg_s_parmatch_smth_bld.F90 index 323853d1..7a53055f 100644 --- a/amgprec/impl/aggregator/amg_s_parmatch_smth_bld.F90 +++ b/amgprec/impl/aggregator/amg_s_parmatch_smth_bld.F90 @@ -69,6 +69,8 @@ ! ! ! Arguments: +! dol1smoothing - Select between l1-Jacobi and Jacobi as smoother for the +! tentative prolongator ! a - type(psb_sspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -102,8 +104,8 @@ ! info - integer, output. ! Error code. ! -subroutine amg_s_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_s_parmatch_smth_bld(dol1smoothing,ag,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_s_inner_mod @@ -116,6 +118,7 @@ subroutine amg_s_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing class(amg_s_parmatch_aggregator_type), target, intent(inout) :: ag type(psb_sspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a @@ -137,7 +140,7 @@ subroutine amg_s_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& type(psb_s_coo_sparse_mat) :: coo_prol, coo_restr type(psb_s_csr_sparse_mat) :: acsrf, csr_prol, acsr, tcsr real(psb_spk_), allocatable :: adiag(:) - real(psb_spk_), allocatable :: arwsum(:) + real(psb_spk_), allocatable :: arwsum(:),l1rwsum(:) logical :: filter_mat integer(psb_ipk_) :: debug_level, debug_unit, err_act integer(psb_ipk_), parameter :: ncmax=16 @@ -145,6 +148,7 @@ subroutine amg_s_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& logical, parameter :: debug_new=.false., dump_r=.false., dump_p=.false., debug=.false. character(len=80) :: filename logical, parameter :: do_timings=.false. + logical :: do_l1correction=.false. integer(psb_ipk_), save :: idx_spspmm=-1, idx_phase1=-1, idx_gtrans=-1, idx_phase2=-1, idx_refine=-1, idx_phase3=-1 integer(psb_ipk_), save :: idx_cdasb=-1, idx_ptap=-1 @@ -166,6 +170,10 @@ subroutine amg_s_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& ncol = desc_a%get_local_cols() theta = parms%aggr_thresh + ! Check if we have to perform l1-Jacobi or Jacobi as smoother + if(dol1smoothing.eq.amg_l1_smooth_prol_) do_l1correction=.true. + + !write(0,*) me,' ',trim(name),' Start ',idx_spspmm if ((do_timings).and.(idx_spspmm==-1)) & & idx_spspmm = psb_get_timer_idx("PMC_SMTH_BLD: par_spspmm") @@ -217,6 +225,19 @@ subroutine amg_s_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& if (info == psb_success_) & & call psb_halo(adiag,desc_a,info) if (info == psb_success_) call a%cp_to(acsr) + ! Get the l1-diagonal of D + if (do_l1correction) then + allocate(l1rwsum(nrow)) + call acsr%arwsum(l1rwsum) + if (info == psb_success_) & + & call psb_realloc(ncol,l1rwsum,info) + if (info == psb_success_) & + & call psb_halo(l1rwsum,desc_a,info) + ! \tilde{D}_{i,i} = \sum_{j \ne i} |a_{i,j}| + do i=1,size(adiag) + adiag(i) = adiag(i) + l1rwsum(i) - abs(adiag(i)) + end do + end if if(info /= psb_success_) then call psb_errpush(psb_err_from_subroutine_,name,a_err='sp_getdiag') @@ -267,7 +288,10 @@ subroutine amg_s_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& if (parms%aggr_omega_alg == amg_eig_est_) then - if (parms%aggr_eig == amg_max_norm_) then + if (do_l1correction) then + ! For l1-Jacobi this can be estimated with 1 + parms%aggr_omega_val = done + else if (parms%aggr_eig == amg_max_norm_) then allocate(arwsum(nrow)) call acsr%arwsum(arwsum) anorm = maxval(abs(adiag(1:nrow)*arwsum(1:nrow))) @@ -373,6 +397,7 @@ subroutine amg_s_parmatch_smth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& end block end if + if (allocated(l1rwsum)) deallocate(l1rwsum) if (do_timings) call psb_toc(idx_phase2) if (debug_level >= psb_debug_outer_) & diff --git a/amgprec/impl/aggregator/amg_s_parmatch_unsmth_bld.F90 b/amgprec/impl/aggregator/amg_s_parmatch_unsmth_bld.F90 index 6fcf65ac..4a96ab95 100644 --- a/amgprec/impl/aggregator/amg_s_parmatch_unsmth_bld.F90 +++ b/amgprec/impl/aggregator/amg_s_parmatch_unsmth_bld.F90 @@ -68,6 +68,8 @@ ! ! ! Arguments: +! dol1smoothing - this not actually used inside unsmoothed aggregation, it +! is used just to perform a check ! a - type(psb_sspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -101,8 +103,8 @@ ! info - integer, output. ! Error code. ! -subroutine amg_s_parmatch_unsmth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_s_parmatch_unsmth_bld(dol1smoothing,ag,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_s_inner_mod @@ -115,6 +117,7 @@ subroutine amg_s_parmatch_unsmth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing class(amg_s_parmatch_aggregator_type), target, intent(inout) :: ag type(psb_sspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a @@ -159,6 +162,11 @@ subroutine amg_s_parmatch_unsmth_bld(ag,a,desc_a,ilaggr,nlaggr,parms,& ictxt = desc_a%get_context() call psb_info(ictxt, me, np) + if (dol1smoothing.ne.amg_no_smooth_) then + info=psb_err_fatal_; + call psb_errpush(info,name,a_err='Are you trying to smooth an unsmoothed aggregation?') + goto 9999 + end if #if !defined(SERIAL_MPI) nglob = desc_a%get_global_rows() diff --git a/amgprec/impl/aggregator/amg_saggrmat_minnrg_bld.f90 b/amgprec/impl/aggregator/amg_saggrmat_minnrg_bld.f90 index a609e382..80a35344 100644 --- a/amgprec/impl/aggregator/amg_saggrmat_minnrg_bld.f90 +++ b/amgprec/impl/aggregator/amg_saggrmat_minnrg_bld.f90 @@ -69,6 +69,7 @@ ! ! ! Arguments: +! dol1smoothing - fictitious integer argument, it is not used inside ! a - type(psb_sspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -104,8 +105,8 @@ ! Error code. ! ! -subroutine amg_saggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_saggrmat_minnrg_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_s_inner_mod, amg_protect_name => amg_saggrmat_minnrg_bld @@ -113,6 +114,7 @@ subroutine amg_saggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_sspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -171,6 +173,13 @@ subroutine amg_saggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& filter_mat = (parms%aggr_filter == amg_filter_mat_) + if (dol1smoothing.ne.amg_no_smooth_) then + info=psb_err_fatal_; + call psb_errpush(info,name,a_err='Are you trying to smooth an unsmoothed aggregation?') + goto 9999 + end if + + !NEEDS TO BE REWORKED !! ! naggr: number of local aggregates diff --git a/amgprec/impl/aggregator/amg_saggrmat_nosmth_bld.f90 b/amgprec/impl/aggregator/amg_saggrmat_nosmth_bld.f90 index ceeca998..fe684d0c 100644 --- a/amgprec/impl/aggregator/amg_saggrmat_nosmth_bld.f90 +++ b/amgprec/impl/aggregator/amg_saggrmat_nosmth_bld.f90 @@ -94,10 +94,11 @@ ! ! info - integer, output. ! Error code. +! dol1smoothing - optional, this is here just for interfacing reasons. It is not used by the +! code ! -! -subroutine amg_saggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_saggrmat_nosmth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_s_inner_mod, amg_protect_name => amg_saggrmat_nosmth_bld @@ -105,6 +106,7 @@ subroutine amg_saggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_sspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -137,6 +139,12 @@ subroutine amg_saggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& ctxt = desc_a%get_context() call psb_info(ctxt, me, np) + if (dol1smoothing.ne.amg_no_smooth_) then + info=psb_err_fatal_; + call psb_errpush(info,name,a_err='Are you trying to smooth an unsmoothed aggregation?') + goto 9999 + end if + nglob = desc_a%get_global_rows() nrow = desc_a%get_local_rows() ncol = desc_a%get_local_cols() diff --git a/amgprec/impl/aggregator/amg_saggrmat_smth_bld.f90 b/amgprec/impl/aggregator/amg_saggrmat_smth_bld.f90 index b70490ba..7cf657eb 100644 --- a/amgprec/impl/aggregator/amg_saggrmat_smth_bld.f90 +++ b/amgprec/impl/aggregator/amg_saggrmat_smth_bld.f90 @@ -69,6 +69,8 @@ ! ! ! Arguments: +! dol1smooth - Integer taking the type of smoother that has to be used +! on the tentative prolongator ! a - type(psb_sspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -102,8 +104,8 @@ ! info - integer, output. ! Error code. ! -subroutine amg_saggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_saggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_s_inner_mod, amg_protect_name => amg_saggrmat_smth_bld @@ -112,6 +114,7 @@ subroutine amg_saggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_sspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -132,7 +135,7 @@ subroutine amg_saggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& type(psb_s_coo_sparse_mat) :: coo_prol, coo_restr type(psb_s_csr_sparse_mat) :: acsr1, acsrf, csr_prol, acsr real(psb_spk_), allocatable :: adiag(:) - real(psb_spk_), allocatable :: arwsum(:) + real(psb_spk_), allocatable :: arwsum(:),l1rwsum(:) integer(psb_ipk_) :: ierr(5) logical :: filter_mat integer(psb_ipk_) :: debug_level, debug_unit, err_act @@ -141,6 +144,7 @@ subroutine amg_saggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& logical, parameter :: debug_new=.false. character(len=80) :: filename logical, parameter :: do_timings=.false. + logical :: do_l1correction=.false. integer(psb_ipk_), save :: idx_spspmm=-1, idx_phase1=-1, idx_gtrans=-1, idx_phase2=-1, idx_refine=-1 integer(psb_ipk_), save :: idx_phase3=-1, idx_cdasb=-1, idx_ptap=-1 @@ -173,6 +177,9 @@ subroutine amg_saggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if ((do_timings).and.(idx_ptap==-1)) & & idx_ptap = psb_get_timer_idx("DEC_SMTH_BLD: ptap_bld ") + ! check if we have to use Jacobi or l1-Jacobi to smooth the tentative prolongator + if (dol1smoothing.eq.amg_l1_smooth_prol_) do_l1correction=.true. + nglob = desc_a%get_global_rows() nrow = desc_a%get_local_rows() @@ -200,6 +207,24 @@ subroutine amg_saggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if (info == psb_success_) & & call psb_halo(adiag,desc_a,info) if (info == psb_success_) call a%cp_to(acsr) + ! + ! Do the l1-correction on the diagonal if it is requested + ! + if (do_l1correction) then + allocate(l1rwsum(nrow)) + call acsr%arwsum(l1rwsum) + if (info == psb_success_) & + & call psb_realloc(ncol,l1rwsum,info) + if (info == psb_success_) & + & call psb_halo(l1rwsum,desc_a,info) + ! \tilde{D}_{i,i} = \sum_{j \ne i} |a_{i,j}| + !$OMP parallel do private(i) schedule(static) + do i=1,size(adiag) + adiag(i) = adiag(i) + l1rwsum(i) - abs(adiag(i)) + end do + !$OMP end parallel do + end if + if(info /= psb_success_) then call psb_errpush(psb_err_from_subroutine_,name,a_err='sp_getdiag') @@ -230,7 +255,7 @@ subroutine amg_saggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& enddo if (jd == -1) then - write(0,*) name,': Warning: there is no diagonal element', i + if (.not.do_l1correction) write(0,*) 'Wrong input: we need the diagonal!!!!', i else acsrf%val(jd)=acsrf%val(jd)-tmp end if @@ -252,14 +277,16 @@ subroutine amg_saggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& !$OMP end parallel do if (parms%aggr_omega_alg == amg_eig_est_) then - if (parms%aggr_eig == amg_max_norm_) then + if (do_l1correction) then + ! For l1-Jacobi this can be estimated with 1 + parms%aggr_omega_val = done + else if (parms%aggr_eig == amg_max_norm_) then allocate(arwsum(nrow)) call acsr%arwsum(arwsum) anorm = maxval(abs(adiag(1:nrow)*arwsum(1:nrow))) call psb_amx(ctxt,anorm) omega = 4.d0/(3.d0*anorm) parms%aggr_omega_val = omega - else info = psb_err_internal_error_ call psb_errpush(info,name,a_err='invalid amg_aggr_eig_') @@ -322,6 +349,7 @@ subroutine amg_saggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if (debug_level >= psb_debug_outer_) & & write(debug_unit,*) me,' ',trim(name),& & 'Done smooth_aggregate ' + if (allocated(l1rwsum)) deallocate(l1rwsum) call psb_erractionrestore(err_act) return diff --git a/amgprec/impl/aggregator/amg_z_dec_aggregator_mat_bld.f90 b/amgprec/impl/aggregator/amg_z_dec_aggregator_mat_bld.f90 index 7135bfc3..e3b9f6af 100644 --- a/amgprec/impl/aggregator/amg_z_dec_aggregator_mat_bld.f90 +++ b/amgprec/impl/aggregator/amg_z_dec_aggregator_mat_bld.f90 @@ -177,23 +177,24 @@ subroutine amg_z_dec_aggregator_mat_bld(ag,parms,a,desc_a,ilaggr,nlaggr,& select case (parms%aggr_prol) case (amg_no_smooth_) - call amg_zaggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,& - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_zaggrmat_nosmth_bld(parms%aggr_prol,a,desc_a,ilaggr,& + nlaggr,parms,ac,desc_ac,op_prol,op_restr,t_prol,info) - case(amg_smooth_prol_) + case(amg_smooth_prol_,amg_l1_smooth_prol_) - call amg_zaggrmat_smth_bld(a,desc_a,ilaggr,nlaggr, & - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_zaggrmat_smth_bld(parms%aggr_prol,a,desc_a,& + ilaggr,nlaggr,parms,ac,desc_ac,op_prol,& + op_restr,t_prol,info) !!$ case(amg_biz_prol_) !!$ !!$ call amg_zaggrmat_biz_bld(a,desc_a,ilaggr,nlaggr, & !!$ & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) - + case(amg_min_energy_) - call amg_zaggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr, & - & parms,ac,desc_ac,op_prol,op_restr,t_prol,info) + call amg_zaggrmat_minnrg_bld(parms%aggr_prol,a,desc_a,ilaggr,& + nlaggr,parms,ac,desc_ac,op_prol,op_restr,t_prol,info) case default info = psb_err_internal_error_ diff --git a/amgprec/impl/aggregator/amg_zaggrmat_minnrg_bld.f90 b/amgprec/impl/aggregator/amg_zaggrmat_minnrg_bld.f90 index 7bafbc18..eaa7f273 100644 --- a/amgprec/impl/aggregator/amg_zaggrmat_minnrg_bld.f90 +++ b/amgprec/impl/aggregator/amg_zaggrmat_minnrg_bld.f90 @@ -69,6 +69,7 @@ ! ! ! Arguments: +! dol1smoothing - fictitious integer argument, it is not used inside ! a - type(psb_zspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -104,8 +105,8 @@ ! Error code. ! ! -subroutine amg_zaggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_zaggrmat_minnrg_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_z_inner_mod, amg_protect_name => amg_zaggrmat_minnrg_bld @@ -113,6 +114,7 @@ subroutine amg_zaggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_zspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -171,6 +173,13 @@ subroutine amg_zaggrmat_minnrg_bld(a,desc_a,ilaggr,nlaggr,parms,& filter_mat = (parms%aggr_filter == amg_filter_mat_) + if (dol1smoothing.ne.amg_no_smooth_) then + info=psb_err_fatal_; + call psb_errpush(info,name,a_err='Are you trying to smooth an unsmoothed aggregation?') + goto 9999 + end if + + !NEEDS TO BE REWORKED !! ! naggr: number of local aggregates diff --git a/amgprec/impl/aggregator/amg_zaggrmat_nosmth_bld.f90 b/amgprec/impl/aggregator/amg_zaggrmat_nosmth_bld.f90 index 6fd53861..2a0b631c 100644 --- a/amgprec/impl/aggregator/amg_zaggrmat_nosmth_bld.f90 +++ b/amgprec/impl/aggregator/amg_zaggrmat_nosmth_bld.f90 @@ -94,10 +94,11 @@ ! ! info - integer, output. ! Error code. +! dol1smoothing - optional, this is here just for interfacing reasons. It is not used by the +! code ! -! -subroutine amg_zaggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_zaggrmat_nosmth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_z_inner_mod, amg_protect_name => amg_zaggrmat_nosmth_bld @@ -105,6 +106,7 @@ subroutine amg_zaggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_zspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -137,6 +139,12 @@ subroutine amg_zaggrmat_nosmth_bld(a,desc_a,ilaggr,nlaggr,parms,& ctxt = desc_a%get_context() call psb_info(ctxt, me, np) + if (dol1smoothing.ne.amg_no_smooth_) then + info=psb_err_fatal_; + call psb_errpush(info,name,a_err='Are you trying to smooth an unsmoothed aggregation?') + goto 9999 + end if + nglob = desc_a%get_global_rows() nrow = desc_a%get_local_rows() ncol = desc_a%get_local_cols() diff --git a/amgprec/impl/aggregator/amg_zaggrmat_smth_bld.f90 b/amgprec/impl/aggregator/amg_zaggrmat_smth_bld.f90 index 11f30589..70dd0ecd 100644 --- a/amgprec/impl/aggregator/amg_zaggrmat_smth_bld.f90 +++ b/amgprec/impl/aggregator/amg_zaggrmat_smth_bld.f90 @@ -69,6 +69,8 @@ ! ! ! Arguments: +! dol1smooth - Integer taking the type of smoother that has to be used +! on the tentative prolongator ! a - type(psb_zspmat_type), input. ! The sparse matrix structure containing the local part of ! the fine-level matrix. @@ -102,8 +104,8 @@ ! info - integer, output. ! Error code. ! -subroutine amg_zaggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& - & ac,desc_ac,op_prol,op_restr,t_prol,info) +subroutine amg_zaggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& + parms,ac,desc_ac,op_prol,op_restr,t_prol,info) use psb_base_mod use amg_base_prec_type use amg_z_inner_mod, amg_protect_name => amg_zaggrmat_smth_bld @@ -112,6 +114,7 @@ subroutine amg_zaggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& implicit none ! Arguments + integer(psb_ipk_), intent(in) :: dol1smoothing type(psb_zspmat_type), intent(in) :: a type(psb_desc_type), intent(inout) :: desc_a integer(psb_lpk_), intent(inout) :: ilaggr(:), nlaggr(:) @@ -132,7 +135,7 @@ subroutine amg_zaggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& type(psb_z_coo_sparse_mat) :: coo_prol, coo_restr type(psb_z_csr_sparse_mat) :: acsr1, acsrf, csr_prol, acsr complex(psb_dpk_), allocatable :: adiag(:) - real(psb_dpk_), allocatable :: arwsum(:) + real(psb_dpk_), allocatable :: arwsum(:),l1rwsum(:) integer(psb_ipk_) :: ierr(5) logical :: filter_mat integer(psb_ipk_) :: debug_level, debug_unit, err_act @@ -141,6 +144,7 @@ subroutine amg_zaggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& logical, parameter :: debug_new=.false. character(len=80) :: filename logical, parameter :: do_timings=.false. + logical :: do_l1correction=.false. integer(psb_ipk_), save :: idx_spspmm=-1, idx_phase1=-1, idx_gtrans=-1, idx_phase2=-1, idx_refine=-1 integer(psb_ipk_), save :: idx_phase3=-1, idx_cdasb=-1, idx_ptap=-1 @@ -173,6 +177,9 @@ subroutine amg_zaggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if ((do_timings).and.(idx_ptap==-1)) & & idx_ptap = psb_get_timer_idx("DEC_SMTH_BLD: ptap_bld ") + ! check if we have to use Jacobi or l1-Jacobi to smooth the tentative prolongator + if (dol1smoothing.eq.amg_l1_smooth_prol_) do_l1correction=.true. + nglob = desc_a%get_global_rows() nrow = desc_a%get_local_rows() @@ -200,6 +207,24 @@ subroutine amg_zaggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if (info == psb_success_) & & call psb_halo(adiag,desc_a,info) if (info == psb_success_) call a%cp_to(acsr) + ! + ! Do the l1-correction on the diagonal if it is requested + ! + if (do_l1correction) then + allocate(l1rwsum(nrow)) + call acsr%arwsum(l1rwsum) + if (info == psb_success_) & + & call psb_realloc(ncol,l1rwsum,info) + if (info == psb_success_) & + & call psb_halo(l1rwsum,desc_a,info) + ! \tilde{D}_{i,i} = \sum_{j \ne i} |a_{i,j}| + !$OMP parallel do private(i) schedule(static) + do i=1,size(adiag) + adiag(i) = adiag(i) + l1rwsum(i) - abs(adiag(i)) + end do + !$OMP end parallel do + end if + if(info /= psb_success_) then call psb_errpush(psb_err_from_subroutine_,name,a_err='sp_getdiag') @@ -230,7 +255,7 @@ subroutine amg_zaggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& enddo if (jd == -1) then - write(0,*) name,': Warning: there is no diagonal element', i + if (.not.do_l1correction) write(0,*) 'Wrong input: we need the diagonal!!!!', i else acsrf%val(jd)=acsrf%val(jd)-tmp end if @@ -252,14 +277,16 @@ subroutine amg_zaggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& !$OMP end parallel do if (parms%aggr_omega_alg == amg_eig_est_) then - if (parms%aggr_eig == amg_max_norm_) then + if (do_l1correction) then + ! For l1-Jacobi this can be estimated with 1 + parms%aggr_omega_val = done + else if (parms%aggr_eig == amg_max_norm_) then allocate(arwsum(nrow)) call acsr%arwsum(arwsum) anorm = maxval(abs(adiag(1:nrow)*arwsum(1:nrow))) call psb_amx(ctxt,anorm) omega = 4.d0/(3.d0*anorm) parms%aggr_omega_val = omega - else info = psb_err_internal_error_ call psb_errpush(info,name,a_err='invalid amg_aggr_eig_') @@ -322,6 +349,7 @@ subroutine amg_zaggrmat_smth_bld(a,desc_a,ilaggr,nlaggr,parms,& if (debug_level >= psb_debug_outer_) & & write(debug_unit,*) me,' ',trim(name),& & 'Done smooth_aggregate ' + if (allocated(l1rwsum)) deallocate(l1rwsum) call psb_erractionrestore(err_act) return From aec5a52c7fe3e2d312fbe6c9c569911d72ede45c Mon Sep 17 00:00:00 2001 From: Salvatore Filippone Date: Wed, 16 Oct 2024 10:56:53 +0200 Subject: [PATCH 03/27] Missing CBIND clean target --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index ecd50936..2dd16629 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,7 @@ cleanlib: veryclean: cleanlib (cd amgprec && $(MAKE) veryclean) + (cd cbind && $(MAKE) veryclean) (cd samples/simple/fileread && $(MAKE) clean) (cd samples/simple/pdegen && $(MAKE) clean) (cd samples/advanced/fileread && $(MAKE) clean) @@ -56,3 +57,4 @@ check: all clean: (cd amgprec && $(MAKE) clean) + (cd cbind && $(MAKE) clean) From 68a9cceaa001e1e72c6c7cb2c7a7000d44b08a89 Mon Sep 17 00:00:00 2001 From: Cirdans-Home Date: Tue, 29 Oct 2024 15:51:37 +0000 Subject: [PATCH 04/27] Fixed l1-Jacobi scaling --- amgprec/impl/aggregator/amg_caggrmat_smth_bld.f90 | 12 +++++++----- amgprec/impl/aggregator/amg_daggrmat_smth_bld.f90 | 12 +++++++----- amgprec/impl/aggregator/amg_saggrmat_smth_bld.f90 | 12 +++++++----- amgprec/impl/aggregator/amg_zaggrmat_smth_bld.f90 | 12 +++++++----- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/amgprec/impl/aggregator/amg_caggrmat_smth_bld.f90 b/amgprec/impl/aggregator/amg_caggrmat_smth_bld.f90 index 4cd75284..e87637cf 100644 --- a/amgprec/impl/aggregator/amg_caggrmat_smth_bld.f90 +++ b/amgprec/impl/aggregator/amg_caggrmat_smth_bld.f90 @@ -255,7 +255,8 @@ subroutine amg_caggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& enddo if (jd == -1) then - if (.not.do_l1correction) write(0,*) 'Wrong input: we need the diagonal!!!!', i + ! if (.not.do_l1correction) + write(0,*) 'Wrong input: we need the diagonal!!!!', i else acsrf%val(jd)=acsrf%val(jd)-tmp end if @@ -277,10 +278,11 @@ subroutine amg_caggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& !$OMP end parallel do if (parms%aggr_omega_alg == amg_eig_est_) then - if (do_l1correction) then - ! For l1-Jacobi this can be estimated with 1 - parms%aggr_omega_val = done - else if (parms%aggr_eig == amg_max_norm_) then + !if (do_l1correction) then + ! ! For l1-Jacobi this can be estimated with 1 + ! parms%aggr_omega_val = done + ! + if (parms%aggr_eig == amg_max_norm_) then allocate(arwsum(nrow)) call acsr%arwsum(arwsum) anorm = maxval(abs(adiag(1:nrow)*arwsum(1:nrow))) diff --git a/amgprec/impl/aggregator/amg_daggrmat_smth_bld.f90 b/amgprec/impl/aggregator/amg_daggrmat_smth_bld.f90 index 399e27b6..5b4f0a92 100644 --- a/amgprec/impl/aggregator/amg_daggrmat_smth_bld.f90 +++ b/amgprec/impl/aggregator/amg_daggrmat_smth_bld.f90 @@ -255,7 +255,8 @@ subroutine amg_daggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& enddo if (jd == -1) then - if (.not.do_l1correction) write(0,*) 'Wrong input: we need the diagonal!!!!', i + ! if (.not.do_l1correction) + write(0,*) 'Wrong input: we need the diagonal!!!!', i else acsrf%val(jd)=acsrf%val(jd)-tmp end if @@ -277,10 +278,11 @@ subroutine amg_daggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& !$OMP end parallel do if (parms%aggr_omega_alg == amg_eig_est_) then - if (do_l1correction) then - ! For l1-Jacobi this can be estimated with 1 - parms%aggr_omega_val = done - else if (parms%aggr_eig == amg_max_norm_) then + !if (do_l1correction) then + ! ! For l1-Jacobi this can be estimated with 1 + ! parms%aggr_omega_val = done + ! + if (parms%aggr_eig == amg_max_norm_) then allocate(arwsum(nrow)) call acsr%arwsum(arwsum) anorm = maxval(abs(adiag(1:nrow)*arwsum(1:nrow))) diff --git a/amgprec/impl/aggregator/amg_saggrmat_smth_bld.f90 b/amgprec/impl/aggregator/amg_saggrmat_smth_bld.f90 index 7cf657eb..1688b369 100644 --- a/amgprec/impl/aggregator/amg_saggrmat_smth_bld.f90 +++ b/amgprec/impl/aggregator/amg_saggrmat_smth_bld.f90 @@ -255,7 +255,8 @@ subroutine amg_saggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& enddo if (jd == -1) then - if (.not.do_l1correction) write(0,*) 'Wrong input: we need the diagonal!!!!', i + ! if (.not.do_l1correction) + write(0,*) 'Wrong input: we need the diagonal!!!!', i else acsrf%val(jd)=acsrf%val(jd)-tmp end if @@ -277,10 +278,11 @@ subroutine amg_saggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& !$OMP end parallel do if (parms%aggr_omega_alg == amg_eig_est_) then - if (do_l1correction) then - ! For l1-Jacobi this can be estimated with 1 - parms%aggr_omega_val = done - else if (parms%aggr_eig == amg_max_norm_) then + !if (do_l1correction) then + ! ! For l1-Jacobi this can be estimated with 1 + ! parms%aggr_omega_val = done + ! + if (parms%aggr_eig == amg_max_norm_) then allocate(arwsum(nrow)) call acsr%arwsum(arwsum) anorm = maxval(abs(adiag(1:nrow)*arwsum(1:nrow))) diff --git a/amgprec/impl/aggregator/amg_zaggrmat_smth_bld.f90 b/amgprec/impl/aggregator/amg_zaggrmat_smth_bld.f90 index 70dd0ecd..d35ac125 100644 --- a/amgprec/impl/aggregator/amg_zaggrmat_smth_bld.f90 +++ b/amgprec/impl/aggregator/amg_zaggrmat_smth_bld.f90 @@ -255,7 +255,8 @@ subroutine amg_zaggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& enddo if (jd == -1) then - if (.not.do_l1correction) write(0,*) 'Wrong input: we need the diagonal!!!!', i + ! if (.not.do_l1correction) + write(0,*) 'Wrong input: we need the diagonal!!!!', i else acsrf%val(jd)=acsrf%val(jd)-tmp end if @@ -277,10 +278,11 @@ subroutine amg_zaggrmat_smth_bld(dol1smoothing,a,desc_a,ilaggr,nlaggr,& !$OMP end parallel do if (parms%aggr_omega_alg == amg_eig_est_) then - if (do_l1correction) then - ! For l1-Jacobi this can be estimated with 1 - parms%aggr_omega_val = done - else if (parms%aggr_eig == amg_max_norm_) then + !if (do_l1correction) then + ! ! For l1-Jacobi this can be estimated with 1 + ! parms%aggr_omega_val = done + ! + if (parms%aggr_eig == amg_max_norm_) then allocate(arwsum(nrow)) call acsr%arwsum(arwsum) anorm = maxval(abs(adiag(1:nrow)*arwsum(1:nrow))) From b704d50df1dfec55c48a0479ade748cfed8b797f Mon Sep 17 00:00:00 2001 From: sfilippone Date: Wed, 30 Oct 2024 10:49:05 +0100 Subject: [PATCH 05/27] Fix dump of TPROL and POLY smoother --- amgprec/impl/level/amg_c_base_onelev_dump.f90 | 6 ++---- amgprec/impl/level/amg_d_base_onelev_dump.f90 | 6 ++---- amgprec/impl/level/amg_s_base_onelev_dump.f90 | 6 ++---- amgprec/impl/level/amg_z_base_onelev_dump.f90 | 6 ++---- amgprec/impl/smoother/amg_d_poly_smoother_dmp.f90 | 4 +--- amgprec/impl/smoother/amg_s_poly_smoother_dmp.f90 | 4 +--- 6 files changed, 10 insertions(+), 22 deletions(-) diff --git a/amgprec/impl/level/amg_c_base_onelev_dump.f90 b/amgprec/impl/level/amg_c_base_onelev_dump.f90 index 14b4c9b6..60e43280 100644 --- a/amgprec/impl/level/amg_c_base_onelev_dump.f90 +++ b/amgprec/impl/level/amg_c_base_onelev_dump.f90 @@ -127,8 +127,7 @@ subroutine amg_c_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& ivr = lv%linmap%p_desc_U%get_global_indices(owned=.false.) write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head,ivr=ivr) + call lv%tprol%print(fname,head=head,ivr=ivr) end if end if else @@ -151,8 +150,7 @@ subroutine amg_c_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& if (tprol_) then write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head) + call lv%tprol%print(fname,head=head) end if end if end if diff --git a/amgprec/impl/level/amg_d_base_onelev_dump.f90 b/amgprec/impl/level/amg_d_base_onelev_dump.f90 index c1013d41..0b3e15f6 100644 --- a/amgprec/impl/level/amg_d_base_onelev_dump.f90 +++ b/amgprec/impl/level/amg_d_base_onelev_dump.f90 @@ -127,8 +127,7 @@ subroutine amg_d_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& ivr = lv%linmap%p_desc_U%get_global_indices(owned=.false.) write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head,ivr=ivr) + call lv%tprol%print(fname,head=head,ivr=ivr) end if end if else @@ -151,8 +150,7 @@ subroutine amg_d_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& if (tprol_) then write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head) + call lv%tprol%print(fname,head=head) end if end if end if diff --git a/amgprec/impl/level/amg_s_base_onelev_dump.f90 b/amgprec/impl/level/amg_s_base_onelev_dump.f90 index d30c0bf7..6fb3454e 100644 --- a/amgprec/impl/level/amg_s_base_onelev_dump.f90 +++ b/amgprec/impl/level/amg_s_base_onelev_dump.f90 @@ -127,8 +127,7 @@ subroutine amg_s_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& ivr = lv%linmap%p_desc_U%get_global_indices(owned=.false.) write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head,ivr=ivr) + call lv%tprol%print(fname,head=head,ivr=ivr) end if end if else @@ -151,8 +150,7 @@ subroutine amg_s_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& if (tprol_) then write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head) + call lv%tprol%print(fname,head=head) end if end if end if diff --git a/amgprec/impl/level/amg_z_base_onelev_dump.f90 b/amgprec/impl/level/amg_z_base_onelev_dump.f90 index 5d0b8f27..49e8eb98 100644 --- a/amgprec/impl/level/amg_z_base_onelev_dump.f90 +++ b/amgprec/impl/level/amg_z_base_onelev_dump.f90 @@ -127,8 +127,7 @@ subroutine amg_z_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& ivr = lv%linmap%p_desc_U%get_global_indices(owned=.false.) write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head,ivr=ivr) + call lv%tprol%print(fname,head=head,ivr=ivr) end if end if else @@ -151,8 +150,7 @@ subroutine amg_z_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& if (tprol_) then write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head) + call lv%tprol%print(fname,head=head) end if end if end if diff --git a/amgprec/impl/smoother/amg_d_poly_smoother_dmp.f90 b/amgprec/impl/smoother/amg_d_poly_smoother_dmp.f90 index 19144f07..296ce7e6 100644 --- a/amgprec/impl/smoother/amg_d_poly_smoother_dmp.f90 +++ b/amgprec/impl/smoother/amg_d_poly_smoother_dmp.f90 @@ -77,11 +77,9 @@ subroutine amg_d_poly_smoother_dmp(sm,desc,level,info,prefix,head,smoother,solve end if lname = len_trim(prefix_) fname = trim(prefix_) - write(fname(lname+1:lname+5),'(a,i3.3)') '_poly',iam + write(fname(lname+1:lname+8),'(a,i3.3)') '_poly',iam lname = lname + 8 ! to be completed - - ! At base level do nothing for the smoother if (allocated(sm%sv)) & diff --git a/amgprec/impl/smoother/amg_s_poly_smoother_dmp.f90 b/amgprec/impl/smoother/amg_s_poly_smoother_dmp.f90 index f6fa2f8a..da16b187 100644 --- a/amgprec/impl/smoother/amg_s_poly_smoother_dmp.f90 +++ b/amgprec/impl/smoother/amg_s_poly_smoother_dmp.f90 @@ -77,11 +77,9 @@ subroutine amg_s_poly_smoother_dmp(sm,desc,level,info,prefix,head,smoother,solve end if lname = len_trim(prefix_) fname = trim(prefix_) - write(fname(lname+1:lname+5),'(a,i3.3)') '_poly',iam + write(fname(lname+1:lname+8),'(a,i3.3)') '_poly',iam lname = lname + 8 ! to be completed - - ! At base level do nothing for the smoother if (allocated(sm%sv)) & From 83ba79d7aeb997bf85331aaa9d61ea667dbce439 Mon Sep 17 00:00:00 2001 From: sfilippone Date: Sat, 2 Nov 2024 10:33:23 +0100 Subject: [PATCH 06/27] Fix input file --- samples/advanced/pdegen/runs/amg_pde2d.inp | 2 +- samples/advanced/pdegen/runs/amg_pde3d.inp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/advanced/pdegen/runs/amg_pde2d.inp b/samples/advanced/pdegen/runs/amg_pde2d.inp index 68b75e6d..f2586a2e 100644 --- a/samples/advanced/pdegen/runs/amg_pde2d.inp +++ b/samples/advanced/pdegen/runs/amg_pde2d.inp @@ -20,7 +20,7 @@ FBGS ! Smoother type JACOBI FBGS GS BWGS BJAC AS POLY r 1 ! degree for polynomial smoother CHEB_4_OPT ! Polynomial variant % Fields to be added for POLY -POLY_RHO_EST_POWER % POLY_RHO_ESTIMATE Currently only POLY_RHO_EST_POWER +POLY_RHO_EST_POWER ! POLY_RHO_ESTIMATE Currently only POLY_RHO_EST_POWER % POLY_RHO_ESTIMATE_ITERATIONS default = 20 % POLY_RHO_BA set to value 1.0 diff --git a/samples/advanced/pdegen/runs/amg_pde3d.inp b/samples/advanced/pdegen/runs/amg_pde3d.inp index d3a7dbda..e78143f0 100644 --- a/samples/advanced/pdegen/runs/amg_pde3d.inp +++ b/samples/advanced/pdegen/runs/amg_pde3d.inp @@ -1,6 +1,6 @@ %%%%%%%%%%% General arguments % Lines starting with % are ignored. CSR ! Storage format CSR COO JAD -0150 ! IDIM; domain size. Linear system size is IDIM**3 +0050 ! IDIM; domain size. Linear system size is IDIM**3 POISSON ! PDECOEFF: POISSON, EXP, BOX, GAUSS % ! Coefficients of the PDE CG ! Iterative method: @@ -20,7 +20,7 @@ POLY ! Smoother type JACOBI FBGS GS BWGS BJAC AS POLY r 6 ! degree for polynomial smoother CHEB_4_OPT ! Polynomial variant % Fields to be added for POLY -POLY_RHO_EST_POWER % POLY_RHO_ESTIMATE Currently only POLY_RHO_EST_POWER +POLY_RHO_EST_POWER ! POLY_RHO_ESTIMATE Currently only POLY_RHO_EST_POWER % POLY_RHO_ESTIMATE_ITERATIONS default = 20 % POLY_RHO_BA set to value 1.0 From 60324084d8ef2b1faae1afc655b089f69564bdf2 Mon Sep 17 00:00:00 2001 From: sfilippone Date: Fri, 8 Nov 2024 18:25:13 +0100 Subject: [PATCH 07/27] New Richardson solver. --- samples/advanced/pdegen/amg_d_pde2d.F90 | 13 ++++++++++--- samples/advanced/pdegen/amg_d_pde3d.F90 | 13 ++++++++++--- samples/advanced/pdegen/amg_s_pde2d.F90 | 13 ++++++++++--- samples/advanced/pdegen/amg_s_pde3d.F90 | 13 ++++++++++--- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/samples/advanced/pdegen/amg_d_pde2d.F90 b/samples/advanced/pdegen/amg_d_pde2d.F90 index 51e1c211..52debd1e 100644 --- a/samples/advanced/pdegen/amg_d_pde2d.F90 +++ b/samples/advanced/pdegen/amg_d_pde2d.F90 @@ -472,9 +472,16 @@ program amg_d_pde2d ! call psb_barrier(ctxt) t1 = psb_wtime() - call psb_krylov(s_choice%kmethd,a,prec,b,x,s_choice%eps,& - & desc_a,info,itmax=s_choice%itmax,iter=iter,err=err,itrace=s_choice%itrace,& - & istop=s_choice%istopc,irst=s_choice%irst) + if (psb_toupper(trim(s_choice%kmethd)) == 'RICHARDSON') then + call psb_richardson(a,prec,b,x,s_choice%eps,& + & desc_a,info,itmax=s_choice%itmax,iter=iter,& + & err=err,itrace=s_choice%itrace,& + & istop=s_choice%istopc) + else + call psb_krylov(s_choice%kmethd,a,prec,b,x,s_choice%eps,& + & desc_a,info,itmax=s_choice%itmax,iter=iter,err=err,itrace=s_choice%itrace,& + & istop=s_choice%istopc,irst=s_choice%irst) + end if call psb_barrier(ctxt) tslv = psb_wtime() - t1 diff --git a/samples/advanced/pdegen/amg_d_pde3d.F90 b/samples/advanced/pdegen/amg_d_pde3d.F90 index 97ae4a1f..eb8b4344 100644 --- a/samples/advanced/pdegen/amg_d_pde3d.F90 +++ b/samples/advanced/pdegen/amg_d_pde3d.F90 @@ -476,9 +476,16 @@ program amg_d_pde3d ! call psb_barrier(ctxt) t1 = psb_wtime() - call psb_krylov(s_choice%kmethd,a,prec,b,x,s_choice%eps,& - & desc_a,info,itmax=s_choice%itmax,iter=iter,err=err,itrace=s_choice%itrace,& - & istop=s_choice%istopc,irst=s_choice%irst) + if (psb_toupper(trim(s_choice%kmethd)) == 'RICHARDSON') then + call psb_richardson(a,prec,b,x,s_choice%eps,& + & desc_a,info,itmax=s_choice%itmax,iter=iter,& + & err=err,itrace=s_choice%itrace,& + & istop=s_choice%istopc) + else + call psb_krylov(s_choice%kmethd,a,prec,b,x,s_choice%eps,& + & desc_a,info,itmax=s_choice%itmax,iter=iter,err=err,itrace=s_choice%itrace,& + & istop=s_choice%istopc,irst=s_choice%irst) + end if call psb_barrier(ctxt) tslv = psb_wtime() - t1 diff --git a/samples/advanced/pdegen/amg_s_pde2d.F90 b/samples/advanced/pdegen/amg_s_pde2d.F90 index 07c38bad..7732bdbb 100644 --- a/samples/advanced/pdegen/amg_s_pde2d.F90 +++ b/samples/advanced/pdegen/amg_s_pde2d.F90 @@ -472,9 +472,16 @@ program amg_s_pde2d ! call psb_barrier(ctxt) t1 = psb_wtime() - call psb_krylov(s_choice%kmethd,a,prec,b,x,s_choice%eps,& - & desc_a,info,itmax=s_choice%itmax,iter=iter,err=err,itrace=s_choice%itrace,& - & istop=s_choice%istopc,irst=s_choice%irst) + if (psb_toupper(trim(s_choice%kmethd)) == 'RICHARDSON') then + call psb_richardson(a,prec,b,x,s_choice%eps,& + & desc_a,info,itmax=s_choice%itmax,iter=iter,& + & err=err,itrace=s_choice%itrace,& + & istop=s_choice%istopc) + else + call psb_krylov(s_choice%kmethd,a,prec,b,x,s_choice%eps,& + & desc_a,info,itmax=s_choice%itmax,iter=iter,err=err,itrace=s_choice%itrace,& + & istop=s_choice%istopc,irst=s_choice%irst) + end if call psb_barrier(ctxt) tslv = psb_wtime() - t1 diff --git a/samples/advanced/pdegen/amg_s_pde3d.F90 b/samples/advanced/pdegen/amg_s_pde3d.F90 index 0ae2bdc8..f6571bdb 100644 --- a/samples/advanced/pdegen/amg_s_pde3d.F90 +++ b/samples/advanced/pdegen/amg_s_pde3d.F90 @@ -476,9 +476,16 @@ program amg_s_pde3d ! call psb_barrier(ctxt) t1 = psb_wtime() - call psb_krylov(s_choice%kmethd,a,prec,b,x,s_choice%eps,& - & desc_a,info,itmax=s_choice%itmax,iter=iter,err=err,itrace=s_choice%itrace,& - & istop=s_choice%istopc,irst=s_choice%irst) + if (psb_toupper(trim(s_choice%kmethd)) == 'RICHARDSON') then + call psb_richardson(a,prec,b,x,s_choice%eps,& + & desc_a,info,itmax=s_choice%itmax,iter=iter,& + & err=err,itrace=s_choice%itrace,& + & istop=s_choice%istopc) + else + call psb_krylov(s_choice%kmethd,a,prec,b,x,s_choice%eps,& + & desc_a,info,itmax=s_choice%itmax,iter=iter,err=err,itrace=s_choice%itrace,& + & istop=s_choice%istopc,irst=s_choice%irst) + end if call psb_barrier(ctxt) tslv = psb_wtime() - t1 From 08a0c744b150b661f90debf5d45d653608f35c29 Mon Sep 17 00:00:00 2001 From: sfilippone Date: Sun, 10 Nov 2024 14:00:51 +0100 Subject: [PATCH 08/27] Switch from KRYLOV to LINSOLVE --- Make_n.inc.in | 2 +- amgprec/impl/level/amg_c_base_onelev_dump.f90 | 6 ++---- amgprec/impl/level/amg_d_base_onelev_dump.f90 | 6 ++---- amgprec/impl/level/amg_s_base_onelev_dump.f90 | 6 ++---- amgprec/impl/level/amg_z_base_onelev_dump.f90 | 6 ++---- amgprec/impl/smoother/amg_c_jac_smoother_apply_vect.f90 | 2 +- amgprec/impl/smoother/amg_d_jac_smoother_apply_vect.f90 | 2 +- amgprec/impl/smoother/amg_d_poly_smoother_apply_vect.f90 | 2 +- amgprec/impl/smoother/amg_s_jac_smoother_apply_vect.f90 | 2 +- amgprec/impl/smoother/amg_s_poly_smoother_apply_vect.f90 | 2 +- amgprec/impl/smoother/amg_z_jac_smoother_apply_vect.f90 | 2 +- amgprec/impl/solver/amg_c_jac_solver_apply.f90 | 2 +- amgprec/impl/solver/amg_c_jac_solver_apply_vect.f90 | 2 +- amgprec/impl/solver/amg_c_krm_solver_impl.f90 | 2 +- amgprec/impl/solver/amg_d_jac_solver_apply.f90 | 2 +- amgprec/impl/solver/amg_d_jac_solver_apply_vect.f90 | 2 +- amgprec/impl/solver/amg_d_krm_solver_impl.f90 | 2 +- amgprec/impl/solver/amg_s_jac_solver_apply.f90 | 2 +- amgprec/impl/solver/amg_s_jac_solver_apply_vect.f90 | 2 +- amgprec/impl/solver/amg_s_krm_solver_impl.f90 | 2 +- amgprec/impl/solver/amg_z_jac_solver_apply.f90 | 2 +- amgprec/impl/solver/amg_z_jac_solver_apply_vect.f90 | 2 +- amgprec/impl/solver/amg_z_krm_solver_impl.f90 | 2 +- config/pac.m4 | 4 ++-- configure | 8 ++++---- configure.ac | 4 ++-- samples/advanced/fileread/Makefile | 2 +- samples/advanced/fileread/amg_cf_sample.f90 | 2 +- samples/advanced/fileread/amg_df_sample.f90 | 2 +- samples/advanced/fileread/amg_sf_sample.f90 | 2 +- samples/advanced/fileread/amg_zf_sample.f90 | 2 +- samples/advanced/pdegen/Makefile | 2 +- samples/advanced/pdegen/amg_d_pde2d.F90 | 2 +- samples/advanced/pdegen/amg_d_pde3d.F90 | 2 +- samples/advanced/pdegen/amg_s_pde2d.F90 | 2 +- samples/advanced/pdegen/amg_s_pde3d.F90 | 2 +- samples/simple/fileread/Makefile | 2 +- samples/simple/fileread/amg_cexample_1lev.f90 | 2 +- samples/simple/fileread/amg_cexample_ml.f90 | 2 +- samples/simple/fileread/amg_dexample_1lev.f90 | 2 +- samples/simple/fileread/amg_dexample_ml.f90 | 2 +- samples/simple/fileread/amg_sexample_1lev.f90 | 2 +- samples/simple/fileread/amg_sexample_ml.f90 | 2 +- samples/simple/fileread/amg_zexample_1lev.f90 | 2 +- samples/simple/fileread/amg_zexample_ml.f90 | 2 +- samples/simple/pdegen/Makefile | 2 +- samples/simple/pdegen/amg_dexample_1lev.f90 | 2 +- samples/simple/pdegen/amg_dexample_ml.f90 | 2 +- samples/simple/pdegen/amg_sexample_1lev.f90 | 2 +- samples/simple/pdegen/amg_sexample_ml.f90 | 2 +- tests/newslv/Makefile | 2 +- 51 files changed, 60 insertions(+), 68 deletions(-) diff --git a/Make_n.inc.in b/Make_n.inc.in index 8fdc622e..d699579d 100644 --- a/Make_n.inc.in +++ b/Make_n.inc.in @@ -49,7 +49,7 @@ PSBLAS_INCLUDES=@PSBLAS_INCLUDES@ PSBLAS_LIBS=@PSBLAS_LIBS@ PSBBASEMODNAME=psb_base_mod PSBPRECMODNAME=psb_prec_mod -PSBMETHDMODNAME=psb_krylov_mod +PSBMETHDMODNAME=psb_linsolve_mod PSBUTILMODNAME=psb_util_mod diff --git a/amgprec/impl/level/amg_c_base_onelev_dump.f90 b/amgprec/impl/level/amg_c_base_onelev_dump.f90 index 14b4c9b6..60e43280 100644 --- a/amgprec/impl/level/amg_c_base_onelev_dump.f90 +++ b/amgprec/impl/level/amg_c_base_onelev_dump.f90 @@ -127,8 +127,7 @@ subroutine amg_c_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& ivr = lv%linmap%p_desc_U%get_global_indices(owned=.false.) write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head,ivr=ivr) + call lv%tprol%print(fname,head=head,ivr=ivr) end if end if else @@ -151,8 +150,7 @@ subroutine amg_c_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& if (tprol_) then write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head) + call lv%tprol%print(fname,head=head) end if end if end if diff --git a/amgprec/impl/level/amg_d_base_onelev_dump.f90 b/amgprec/impl/level/amg_d_base_onelev_dump.f90 index c1013d41..0b3e15f6 100644 --- a/amgprec/impl/level/amg_d_base_onelev_dump.f90 +++ b/amgprec/impl/level/amg_d_base_onelev_dump.f90 @@ -127,8 +127,7 @@ subroutine amg_d_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& ivr = lv%linmap%p_desc_U%get_global_indices(owned=.false.) write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head,ivr=ivr) + call lv%tprol%print(fname,head=head,ivr=ivr) end if end if else @@ -151,8 +150,7 @@ subroutine amg_d_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& if (tprol_) then write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head) + call lv%tprol%print(fname,head=head) end if end if end if diff --git a/amgprec/impl/level/amg_s_base_onelev_dump.f90 b/amgprec/impl/level/amg_s_base_onelev_dump.f90 index d30c0bf7..6fb3454e 100644 --- a/amgprec/impl/level/amg_s_base_onelev_dump.f90 +++ b/amgprec/impl/level/amg_s_base_onelev_dump.f90 @@ -127,8 +127,7 @@ subroutine amg_s_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& ivr = lv%linmap%p_desc_U%get_global_indices(owned=.false.) write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head,ivr=ivr) + call lv%tprol%print(fname,head=head,ivr=ivr) end if end if else @@ -151,8 +150,7 @@ subroutine amg_s_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& if (tprol_) then write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head) + call lv%tprol%print(fname,head=head) end if end if end if diff --git a/amgprec/impl/level/amg_z_base_onelev_dump.f90 b/amgprec/impl/level/amg_z_base_onelev_dump.f90 index 5d0b8f27..49e8eb98 100644 --- a/amgprec/impl/level/amg_z_base_onelev_dump.f90 +++ b/amgprec/impl/level/amg_z_base_onelev_dump.f90 @@ -127,8 +127,7 @@ subroutine amg_z_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& ivr = lv%linmap%p_desc_U%get_global_indices(owned=.false.) write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head,ivr=ivr) + call lv%tprol%print(fname,head=head,ivr=ivr) end if end if else @@ -151,8 +150,7 @@ subroutine amg_z_base_onelev_dump(lv,level,info,prefix,head,ac,rp,& if (tprol_) then write(fname(lname+1:),'(a,i3.3,a)')'_l',level,'_tprol.mtx' ! - ! This is not implemented yet. - !call lv%tprol%print(fname,head=head) + call lv%tprol%print(fname,head=head) end if end if end if diff --git a/amgprec/impl/smoother/amg_c_jac_smoother_apply_vect.f90 b/amgprec/impl/smoother/amg_c_jac_smoother_apply_vect.f90 index a4238980..6d32e2e2 100644 --- a/amgprec/impl/smoother/amg_c_jac_smoother_apply_vect.f90 +++ b/amgprec/impl/smoother/amg_c_jac_smoother_apply_vect.f90 @@ -40,7 +40,7 @@ subroutine amg_c_jac_smoother_apply_vect(alpha,sm,x,beta,y,desc_data,trans,& use psb_base_mod use amg_c_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_c_jac_smoother, amg_protect_name => amg_c_jac_smoother_apply_vect implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/smoother/amg_d_jac_smoother_apply_vect.f90 b/amgprec/impl/smoother/amg_d_jac_smoother_apply_vect.f90 index cafb6c8c..b1148119 100644 --- a/amgprec/impl/smoother/amg_d_jac_smoother_apply_vect.f90 +++ b/amgprec/impl/smoother/amg_d_jac_smoother_apply_vect.f90 @@ -40,7 +40,7 @@ subroutine amg_d_jac_smoother_apply_vect(alpha,sm,x,beta,y,desc_data,trans,& use psb_base_mod use amg_d_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_d_jac_smoother, amg_protect_name => amg_d_jac_smoother_apply_vect implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/smoother/amg_d_poly_smoother_apply_vect.f90 b/amgprec/impl/smoother/amg_d_poly_smoother_apply_vect.f90 index 7cfa7c3d..6ea8444d 100644 --- a/amgprec/impl/smoother/amg_d_poly_smoother_apply_vect.f90 +++ b/amgprec/impl/smoother/amg_d_poly_smoother_apply_vect.f90 @@ -40,7 +40,7 @@ subroutine amg_d_poly_smoother_apply_vect(alpha,sm,x,beta,y,desc_data,trans,& use psb_base_mod use amg_d_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_d_poly_smoother, amg_protect_name => amg_d_poly_smoother_apply_vect implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/smoother/amg_s_jac_smoother_apply_vect.f90 b/amgprec/impl/smoother/amg_s_jac_smoother_apply_vect.f90 index fff7ac1e..1bbb390f 100644 --- a/amgprec/impl/smoother/amg_s_jac_smoother_apply_vect.f90 +++ b/amgprec/impl/smoother/amg_s_jac_smoother_apply_vect.f90 @@ -40,7 +40,7 @@ subroutine amg_s_jac_smoother_apply_vect(alpha,sm,x,beta,y,desc_data,trans,& use psb_base_mod use amg_s_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_s_jac_smoother, amg_protect_name => amg_s_jac_smoother_apply_vect implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/smoother/amg_s_poly_smoother_apply_vect.f90 b/amgprec/impl/smoother/amg_s_poly_smoother_apply_vect.f90 index b5807873..cdf93b7d 100644 --- a/amgprec/impl/smoother/amg_s_poly_smoother_apply_vect.f90 +++ b/amgprec/impl/smoother/amg_s_poly_smoother_apply_vect.f90 @@ -40,7 +40,7 @@ subroutine amg_s_poly_smoother_apply_vect(alpha,sm,x,beta,y,desc_data,trans,& use psb_base_mod use amg_s_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_s_poly_smoother, amg_protect_name => amg_s_poly_smoother_apply_vect implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/smoother/amg_z_jac_smoother_apply_vect.f90 b/amgprec/impl/smoother/amg_z_jac_smoother_apply_vect.f90 index 16d2a484..03bc6095 100644 --- a/amgprec/impl/smoother/amg_z_jac_smoother_apply_vect.f90 +++ b/amgprec/impl/smoother/amg_z_jac_smoother_apply_vect.f90 @@ -40,7 +40,7 @@ subroutine amg_z_jac_smoother_apply_vect(alpha,sm,x,beta,y,desc_data,trans,& use psb_base_mod use amg_z_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_z_jac_smoother, amg_protect_name => amg_z_jac_smoother_apply_vect implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/solver/amg_c_jac_solver_apply.f90 b/amgprec/impl/solver/amg_c_jac_solver_apply.f90 index 6eec4e5e..d47a9f6b 100644 --- a/amgprec/impl/solver/amg_c_jac_solver_apply.f90 +++ b/amgprec/impl/solver/amg_c_jac_solver_apply.f90 @@ -40,7 +40,7 @@ subroutine amg_c_jac_solver_apply(alpha,sv,x,beta,y,desc_data,trans,& use psb_base_mod use amg_c_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_c_jac_solver, amg_protect_name => amg_c_jac_solver_apply implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/solver/amg_c_jac_solver_apply_vect.f90 b/amgprec/impl/solver/amg_c_jac_solver_apply_vect.f90 index 7d48442e..1fccaf63 100644 --- a/amgprec/impl/solver/amg_c_jac_solver_apply_vect.f90 +++ b/amgprec/impl/solver/amg_c_jac_solver_apply_vect.f90 @@ -40,7 +40,7 @@ subroutine amg_c_jac_solver_apply_vect(alpha,sv,x,beta,y,desc_data,trans,& use psb_base_mod use amg_c_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_c_jac_solver, amg_protect_name => amg_c_jac_solver_apply_vect implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/solver/amg_c_krm_solver_impl.f90 b/amgprec/impl/solver/amg_c_krm_solver_impl.f90 index 3c93488f..fe3cb53a 100644 --- a/amgprec/impl/solver/amg_c_krm_solver_impl.f90 +++ b/amgprec/impl/solver/amg_c_krm_solver_impl.f90 @@ -169,7 +169,7 @@ subroutine amg_c_krm_solver_apply_vect(alpha,sv,x,beta,y,desc_data,& & trans,work,wv,info,init,initu) use psb_base_mod - use psb_krylov_mod + use psb_linsolve_mod use amg_c_krm_solver, amg_protect_name => amg_c_krm_solver_apply_vect Implicit None diff --git a/amgprec/impl/solver/amg_d_jac_solver_apply.f90 b/amgprec/impl/solver/amg_d_jac_solver_apply.f90 index 4e5b9421..9a37a162 100644 --- a/amgprec/impl/solver/amg_d_jac_solver_apply.f90 +++ b/amgprec/impl/solver/amg_d_jac_solver_apply.f90 @@ -40,7 +40,7 @@ subroutine amg_d_jac_solver_apply(alpha,sv,x,beta,y,desc_data,trans,& use psb_base_mod use amg_d_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_d_jac_solver, amg_protect_name => amg_d_jac_solver_apply implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/solver/amg_d_jac_solver_apply_vect.f90 b/amgprec/impl/solver/amg_d_jac_solver_apply_vect.f90 index bc35f7ea..ab6b943c 100644 --- a/amgprec/impl/solver/amg_d_jac_solver_apply_vect.f90 +++ b/amgprec/impl/solver/amg_d_jac_solver_apply_vect.f90 @@ -40,7 +40,7 @@ subroutine amg_d_jac_solver_apply_vect(alpha,sv,x,beta,y,desc_data,trans,& use psb_base_mod use amg_d_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_d_jac_solver, amg_protect_name => amg_d_jac_solver_apply_vect implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/solver/amg_d_krm_solver_impl.f90 b/amgprec/impl/solver/amg_d_krm_solver_impl.f90 index dd308157..b955a8d6 100644 --- a/amgprec/impl/solver/amg_d_krm_solver_impl.f90 +++ b/amgprec/impl/solver/amg_d_krm_solver_impl.f90 @@ -169,7 +169,7 @@ subroutine amg_d_krm_solver_apply_vect(alpha,sv,x,beta,y,desc_data,& & trans,work,wv,info,init,initu) use psb_base_mod - use psb_krylov_mod + use psb_linsolve_mod use amg_d_krm_solver, amg_protect_name => amg_d_krm_solver_apply_vect Implicit None diff --git a/amgprec/impl/solver/amg_s_jac_solver_apply.f90 b/amgprec/impl/solver/amg_s_jac_solver_apply.f90 index 500391c8..217f8027 100644 --- a/amgprec/impl/solver/amg_s_jac_solver_apply.f90 +++ b/amgprec/impl/solver/amg_s_jac_solver_apply.f90 @@ -40,7 +40,7 @@ subroutine amg_s_jac_solver_apply(alpha,sv,x,beta,y,desc_data,trans,& use psb_base_mod use amg_s_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_s_jac_solver, amg_protect_name => amg_s_jac_solver_apply implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/solver/amg_s_jac_solver_apply_vect.f90 b/amgprec/impl/solver/amg_s_jac_solver_apply_vect.f90 index da84ffea..7dc5b9ad 100644 --- a/amgprec/impl/solver/amg_s_jac_solver_apply_vect.f90 +++ b/amgprec/impl/solver/amg_s_jac_solver_apply_vect.f90 @@ -40,7 +40,7 @@ subroutine amg_s_jac_solver_apply_vect(alpha,sv,x,beta,y,desc_data,trans,& use psb_base_mod use amg_s_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_s_jac_solver, amg_protect_name => amg_s_jac_solver_apply_vect implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/solver/amg_s_krm_solver_impl.f90 b/amgprec/impl/solver/amg_s_krm_solver_impl.f90 index 1b0efd1b..b2d3d0e5 100644 --- a/amgprec/impl/solver/amg_s_krm_solver_impl.f90 +++ b/amgprec/impl/solver/amg_s_krm_solver_impl.f90 @@ -169,7 +169,7 @@ subroutine amg_s_krm_solver_apply_vect(alpha,sv,x,beta,y,desc_data,& & trans,work,wv,info,init,initu) use psb_base_mod - use psb_krylov_mod + use psb_linsolve_mod use amg_s_krm_solver, amg_protect_name => amg_s_krm_solver_apply_vect Implicit None diff --git a/amgprec/impl/solver/amg_z_jac_solver_apply.f90 b/amgprec/impl/solver/amg_z_jac_solver_apply.f90 index 12288551..f55745bb 100644 --- a/amgprec/impl/solver/amg_z_jac_solver_apply.f90 +++ b/amgprec/impl/solver/amg_z_jac_solver_apply.f90 @@ -40,7 +40,7 @@ subroutine amg_z_jac_solver_apply(alpha,sv,x,beta,y,desc_data,trans,& use psb_base_mod use amg_z_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_z_jac_solver, amg_protect_name => amg_z_jac_solver_apply implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/solver/amg_z_jac_solver_apply_vect.f90 b/amgprec/impl/solver/amg_z_jac_solver_apply_vect.f90 index 241797e8..a97a21a0 100644 --- a/amgprec/impl/solver/amg_z_jac_solver_apply_vect.f90 +++ b/amgprec/impl/solver/amg_z_jac_solver_apply_vect.f90 @@ -40,7 +40,7 @@ subroutine amg_z_jac_solver_apply_vect(alpha,sv,x,beta,y,desc_data,trans,& use psb_base_mod use amg_z_diag_solver - use psb_base_krylov_conv_mod, only : log_conv + use psb_base_linsolve_conv_mod, only : log_conv use amg_z_jac_solver, amg_protect_name => amg_z_jac_solver_apply_vect implicit none type(psb_desc_type), intent(in) :: desc_data diff --git a/amgprec/impl/solver/amg_z_krm_solver_impl.f90 b/amgprec/impl/solver/amg_z_krm_solver_impl.f90 index 33972c4b..ca5d7125 100644 --- a/amgprec/impl/solver/amg_z_krm_solver_impl.f90 +++ b/amgprec/impl/solver/amg_z_krm_solver_impl.f90 @@ -169,7 +169,7 @@ subroutine amg_z_krm_solver_apply_vect(alpha,sv,x,beta,y,desc_data,& & trans,work,wv,info,init,initu) use psb_base_mod - use psb_krylov_mod + use psb_linsolve_mod use amg_z_krm_solver, amg_protect_name => amg_z_krm_solver_apply_vect Implicit None diff --git a/config/pac.m4 b/config/pac.m4 index c0ad6f45..099c5a41 100644 --- a/config/pac.m4 +++ b/config/pac.m4 @@ -409,7 +409,7 @@ save_LDFLAGS=$LDFLAGS; ## dnl AC_MSG_NOTICE([psblas dir $pac_cv_psblas_dir]) ## PSBLAS_LIBS="-L$pac_cv_psblas_dir/lib" ## fi -PSBLAS_LIBS="-lpsb_krylov -lpsb_prec -lpsb_util -lpsb_base -L$PSBLAS_LIBDIR" +PSBLAS_LIBS="-lpsb_linsolve -lpsb_prec -lpsb_util -lpsb_base -L$PSBLAS_LIBDIR" LDFLAGS=" $PSBLAS_LIBS $save_LDFLAGS" dnl ac_compile='${MPIFC-$FC} -c -o conftest${ac_objext} $FMFLAG$PSBLAS_DIR/include $FMFLAG$PSBLAS_DIR/lib conftest.$ac_ext 1>&5' @@ -484,7 +484,7 @@ dnl AC_MSG_NOTICE([psblas dir $pac_cv_psblas_dir]) PSBLAS_INCLUDES="$FMFLAG$pac_cv_psblas_dir/modules $PSBLAS_INCLUDES" fi FCFLAGS=" $PSBLAS_INCLUDES $save_FCFLAGS" -PSBLAS_LIBS="-lpsb_krylov -lpsb_prec -lpsb_util -lpsb_base $PSBLAS_LIBS" +PSBLAS_LIBS="-lpsb_linsolve -lpsb_prec -lpsb_util -lpsb_base $PSBLAS_LIBS" LDFLAGS=" $PSBLAS_LIBS $save_LDFLAGS" dnl ac_compile='${MPIFC-$FC} -c -o conftest${ac_objext} $FMFLAG$PSBLAS_DIR/include $FMFLAG$PSBLAS_DIR/lib conftest.$ac_ext 1>&5' diff --git a/configure b/configure index 8f1485a7..5ce85c96 100755 --- a/configure +++ b/configure @@ -7417,7 +7417,7 @@ then FIFLAG="-I" BASEMODNAME=PSB_BASE_MOD PRECMODNAME=PSB_PREC_MOD - METHDMODNAME=PSB_KRYLOV_MOD + METHDMODNAME=PSB_LINSOLVE_MOD UTILMODNAME=PSB_UTIL_MOD else @@ -7550,7 +7550,7 @@ printf "%s\n" "$ax_cv_f90_modflag" >&6; } FIFLAG=-I BASEMODNAME=psb_base_mod PRECMODNAME=psb_prec_mod - METHDMODNAME=psb_krylov_mod + METHDMODNAME=psb_linsolve_mod UTILMODNAME=psb_util_mod fi @@ -7683,7 +7683,7 @@ save_LDFLAGS=$LDFLAGS; ## dnl AC_MSG_NOTICE([psblas dir $pac_cv_psblas_dir]) ## PSBLAS_LIBS="-L$pac_cv_psblas_dir/lib" ## fi -PSBLAS_LIBS="-lpsb_krylov -lpsb_prec -lpsb_util -lpsb_base -L$PSBLAS_LIBDIR" +PSBLAS_LIBS="-lpsb_linsolve -lpsb_prec -lpsb_util -lpsb_base -L$PSBLAS_LIBDIR" LDFLAGS=" $PSBLAS_LIBS $save_LDFLAGS" ac_link='${MPIFC-$FC} -o conftest${ac_exeext} $FCFLAGS conftest.$ac_ext $LDFLAGS $LIBS 1>&5' @@ -7787,7 +7787,7 @@ elif test "x$pac_cv_psblas_dir" != "x"; then PSBLAS_INCLUDES="$FMFLAG$pac_cv_psblas_dir/modules $PSBLAS_INCLUDES" fi FCFLAGS=" $PSBLAS_INCLUDES $save_FCFLAGS" -PSBLAS_LIBS="-lpsb_krylov -lpsb_prec -lpsb_util -lpsb_base $PSBLAS_LIBS" +PSBLAS_LIBS="-lpsb_linsolve -lpsb_prec -lpsb_util -lpsb_base $PSBLAS_LIBS" LDFLAGS=" $PSBLAS_LIBS $save_LDFLAGS" diff --git a/configure.ac b/configure.ac index 7f13fa95..39380cce 100755 --- a/configure.ac +++ b/configure.ac @@ -525,7 +525,7 @@ then FIFLAG="-I" BASEMODNAME=PSB_BASE_MOD PRECMODNAME=PSB_PREC_MOD - METHDMODNAME=PSB_KRYLOV_MOD + METHDMODNAME=PSB_LINSOLVE_MOD UTILMODNAME=PSB_UTIL_MOD else @@ -536,7 +536,7 @@ else FIFLAG=-I BASEMODNAME=psb_base_mod PRECMODNAME=psb_prec_mod - METHDMODNAME=psb_krylov_mod + METHDMODNAME=psb_linsolve_mod UTILMODNAME=psb_util_mod fi diff --git a/samples/advanced/fileread/Makefile b/samples/advanced/fileread/Makefile index d012036a..87b74cdc 100644 --- a/samples/advanced/fileread/Makefile +++ b/samples/advanced/fileread/Makefile @@ -3,7 +3,7 @@ AMGINCDIR=$(AMGDIR)/include include $(AMGINCDIR)/Make.inc.amg4psblas AMGMODDIR=$(AMGDIR)/modules AMGLIBDIR=$(AMGDIR)/lib -AMG_LIBS=-L$(AMGLIBDIR) -lpsb_krylov -lamg_prec -lpsb_prec +AMG_LIBS=-L$(AMGLIBDIR) -lpsb_linsolve -lamg_prec -lpsb_prec FINCLUDES=$(FMFLAG). $(FMFLAG)$(AMGMODDIR) $(FMFLAG)$(AMGINCDIR) $(PSBLAS_INCLUDES) $(FIFLAG). DFSOBJS=amg_df_sample.o data_input.o diff --git a/samples/advanced/fileread/amg_cf_sample.f90 b/samples/advanced/fileread/amg_cf_sample.f90 index 3fc9f195..10e5753d 100644 --- a/samples/advanced/fileread/amg_cf_sample.f90 +++ b/samples/advanced/fileread/amg_cf_sample.f90 @@ -38,7 +38,7 @@ program amg_cf_sample use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input implicit none diff --git a/samples/advanced/fileread/amg_df_sample.f90 b/samples/advanced/fileread/amg_df_sample.f90 index 381b0a4d..3b590dec 100644 --- a/samples/advanced/fileread/amg_df_sample.f90 +++ b/samples/advanced/fileread/amg_df_sample.f90 @@ -38,7 +38,7 @@ program amg_df_sample use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input implicit none diff --git a/samples/advanced/fileread/amg_sf_sample.f90 b/samples/advanced/fileread/amg_sf_sample.f90 index 15988b4d..2dab82a8 100644 --- a/samples/advanced/fileread/amg_sf_sample.f90 +++ b/samples/advanced/fileread/amg_sf_sample.f90 @@ -38,7 +38,7 @@ program amg_sf_sample use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input implicit none diff --git a/samples/advanced/fileread/amg_zf_sample.f90 b/samples/advanced/fileread/amg_zf_sample.f90 index edb6e51f..4836fb59 100644 --- a/samples/advanced/fileread/amg_zf_sample.f90 +++ b/samples/advanced/fileread/amg_zf_sample.f90 @@ -38,7 +38,7 @@ program amg_zf_sample use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input implicit none diff --git a/samples/advanced/pdegen/Makefile b/samples/advanced/pdegen/Makefile index 4154aaef..31890a98 100644 --- a/samples/advanced/pdegen/Makefile +++ b/samples/advanced/pdegen/Makefile @@ -3,7 +3,7 @@ AMGINCDIR=$(AMGDIR)/include include $(AMGINCDIR)/Make.inc.amg4psblas AMGMODDIR=$(AMGDIR)/modules AMGLIBDIR=$(AMGDIR)/lib -AMG_LIBS=-L$(AMGLIBDIR) -lpsb_krylov -lamg_prec -lpsb_prec +AMG_LIBS=-L$(AMGLIBDIR) -lpsb_linsolve -lamg_prec -lpsb_prec FINCLUDES=$(FMFLAG). $(FMFLAG)$(AMGMODDIR) $(FMFLAG)$(AMGINCDIR) $(PSBLAS_INCLUDES) $(FIFLAG). LINKOPT= diff --git a/samples/advanced/pdegen/amg_d_pde2d.F90 b/samples/advanced/pdegen/amg_d_pde2d.F90 index 52debd1e..33b9b7f0 100644 --- a/samples/advanced/pdegen/amg_d_pde2d.F90 +++ b/samples/advanced/pdegen/amg_d_pde2d.F90 @@ -66,7 +66,7 @@ program amg_d_pde2d use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input use amg_d_pde2d_poisson_mod diff --git a/samples/advanced/pdegen/amg_d_pde3d.F90 b/samples/advanced/pdegen/amg_d_pde3d.F90 index eb8b4344..1b064b24 100644 --- a/samples/advanced/pdegen/amg_d_pde3d.F90 +++ b/samples/advanced/pdegen/amg_d_pde3d.F90 @@ -67,7 +67,7 @@ program amg_d_pde3d use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input use amg_d_pde3d_poisson_mod diff --git a/samples/advanced/pdegen/amg_s_pde2d.F90 b/samples/advanced/pdegen/amg_s_pde2d.F90 index 7732bdbb..53ff650d 100644 --- a/samples/advanced/pdegen/amg_s_pde2d.F90 +++ b/samples/advanced/pdegen/amg_s_pde2d.F90 @@ -66,7 +66,7 @@ program amg_s_pde2d use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input use amg_s_pde2d_poisson_mod diff --git a/samples/advanced/pdegen/amg_s_pde3d.F90 b/samples/advanced/pdegen/amg_s_pde3d.F90 index f6571bdb..91df58a3 100644 --- a/samples/advanced/pdegen/amg_s_pde3d.F90 +++ b/samples/advanced/pdegen/amg_s_pde3d.F90 @@ -67,7 +67,7 @@ program amg_s_pde3d use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input use amg_s_pde3d_poisson_mod diff --git a/samples/simple/fileread/Makefile b/samples/simple/fileread/Makefile index 6f36ed04..ed53ddc9 100644 --- a/samples/simple/fileread/Makefile +++ b/samples/simple/fileread/Makefile @@ -3,7 +3,7 @@ AMGINCDIR=$(AMGDIR)/include include $(AMGINCDIR)/Make.inc.amg4psblas AMGMODDIR=$(AMGDIR)/modules AMGLIBDIR=$(AMGDIR)/lib -AMG_LIBS=-L$(AMGLIBDIR) -lpsb_krylov -lamg_prec -lpsb_prec +AMG_LIBS=-L$(AMGLIBDIR) -lpsb_linsolve -lamg_prec -lpsb_prec FINCLUDES=$(FMFLAG). $(FMFLAG)$(AMGMODDIR) $(FMFLAG)$(AMGINCDIR) $(PSBLAS_INCLUDES) $(FIFLAG). LINKOPT= diff --git a/samples/simple/fileread/amg_cexample_1lev.f90 b/samples/simple/fileread/amg_cexample_1lev.f90 index fa89c3a9..30dcd46c 100644 --- a/samples/simple/fileread/amg_cexample_1lev.f90 +++ b/samples/simple/fileread/amg_cexample_1lev.f90 @@ -47,7 +47,7 @@ program amg_cexample_1lev use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input implicit none diff --git a/samples/simple/fileread/amg_cexample_ml.f90 b/samples/simple/fileread/amg_cexample_ml.f90 index 7a05c4b3..f5f3d927 100644 --- a/samples/simple/fileread/amg_cexample_ml.f90 +++ b/samples/simple/fileread/amg_cexample_ml.f90 @@ -62,7 +62,7 @@ program amg_cexample_ml use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input diff --git a/samples/simple/fileread/amg_dexample_1lev.f90 b/samples/simple/fileread/amg_dexample_1lev.f90 index abef315e..86831925 100644 --- a/samples/simple/fileread/amg_dexample_1lev.f90 +++ b/samples/simple/fileread/amg_dexample_1lev.f90 @@ -47,7 +47,7 @@ program amg_dexample_1lev use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input implicit none diff --git a/samples/simple/fileread/amg_dexample_ml.f90 b/samples/simple/fileread/amg_dexample_ml.f90 index ddc1c021..5a97f590 100644 --- a/samples/simple/fileread/amg_dexample_ml.f90 +++ b/samples/simple/fileread/amg_dexample_ml.f90 @@ -62,7 +62,7 @@ program amg_dexample_ml use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input diff --git a/samples/simple/fileread/amg_sexample_1lev.f90 b/samples/simple/fileread/amg_sexample_1lev.f90 index b30c0e81..03015c8d 100644 --- a/samples/simple/fileread/amg_sexample_1lev.f90 +++ b/samples/simple/fileread/amg_sexample_1lev.f90 @@ -47,7 +47,7 @@ program amg_sexample_1lev use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input implicit none diff --git a/samples/simple/fileread/amg_sexample_ml.f90 b/samples/simple/fileread/amg_sexample_ml.f90 index 3f3e3071..f0f0e77f 100644 --- a/samples/simple/fileread/amg_sexample_ml.f90 +++ b/samples/simple/fileread/amg_sexample_ml.f90 @@ -62,7 +62,7 @@ program amg_sexample_ml use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input diff --git a/samples/simple/fileread/amg_zexample_1lev.f90 b/samples/simple/fileread/amg_zexample_1lev.f90 index cea1a1c5..86cf8caf 100644 --- a/samples/simple/fileread/amg_zexample_1lev.f90 +++ b/samples/simple/fileread/amg_zexample_1lev.f90 @@ -47,7 +47,7 @@ program amg_zexample_1lev use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input implicit none diff --git a/samples/simple/fileread/amg_zexample_ml.f90 b/samples/simple/fileread/amg_zexample_ml.f90 index e6c48d79..369e2a33 100644 --- a/samples/simple/fileread/amg_zexample_ml.f90 +++ b/samples/simple/fileread/amg_zexample_ml.f90 @@ -62,7 +62,7 @@ program amg_zexample_ml use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input diff --git a/samples/simple/pdegen/Makefile b/samples/simple/pdegen/Makefile index 198654d5..cc93e7d3 100644 --- a/samples/simple/pdegen/Makefile +++ b/samples/simple/pdegen/Makefile @@ -3,7 +3,7 @@ AMGINCDIR=$(AMGDIR)/include include $(AMGINCDIR)/Make.inc.amg4psblas AMGMODDIR=$(AMGDIR)/modules AMGLIBDIR=$(AMGDIR)/lib -AMG_LIBS=-L$(AMGLIBDIR) -lpsb_krylov -lamg_prec -lpsb_prec +AMG_LIBS=-L$(AMGLIBDIR) -lpsb_linsolve -lamg_prec -lpsb_prec FINCLUDES=$(FMFLAG). $(FMFLAG)$(AMGMODDIR) $(FMFLAG)$(AMGINCDIR) $(PSBLAS_INCLUDES) $(FIFLAG). LINKOPT= diff --git a/samples/simple/pdegen/amg_dexample_1lev.f90 b/samples/simple/pdegen/amg_dexample_1lev.f90 index 51aa64b2..05158ab1 100644 --- a/samples/simple/pdegen/amg_dexample_1lev.f90 +++ b/samples/simple/pdegen/amg_dexample_1lev.f90 @@ -60,7 +60,7 @@ program amg_dexample_1lev use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input use amg_d_pde_mod diff --git a/samples/simple/pdegen/amg_dexample_ml.f90 b/samples/simple/pdegen/amg_dexample_ml.f90 index 757d19ec..36ada4f5 100644 --- a/samples/simple/pdegen/amg_dexample_ml.f90 +++ b/samples/simple/pdegen/amg_dexample_ml.f90 @@ -83,7 +83,7 @@ program amg_dexample_ml use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input use amg_d_pde_mod diff --git a/samples/simple/pdegen/amg_sexample_1lev.f90 b/samples/simple/pdegen/amg_sexample_1lev.f90 index c47cf9e2..cbfe691b 100644 --- a/samples/simple/pdegen/amg_sexample_1lev.f90 +++ b/samples/simple/pdegen/amg_sexample_1lev.f90 @@ -60,7 +60,7 @@ program amg_sexample_1lev use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input use amg_s_pde_mod diff --git a/samples/simple/pdegen/amg_sexample_ml.f90 b/samples/simple/pdegen/amg_sexample_ml.f90 index 8a00af88..9ae25e6b 100644 --- a/samples/simple/pdegen/amg_sexample_ml.f90 +++ b/samples/simple/pdegen/amg_sexample_ml.f90 @@ -83,7 +83,7 @@ program amg_sexample_ml use psb_base_mod use amg_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_util_mod use data_input use amg_s_pde_mod diff --git a/tests/newslv/Makefile b/tests/newslv/Makefile index 3b9cc19f..76fd30c0 100644 --- a/tests/newslv/Makefile +++ b/tests/newslv/Makefile @@ -3,7 +3,7 @@ MLDINCDIR=$(MLDDIR)/include include $(MLDINCDIR)/Make.inc.amg4psblas MLDMODDIR=$(MLDDIR)/modules MLDLIBDIR=$(MLDDIR)/lib -MLD_LIBS=-L$(MLDLIBDIR) -lpsb_krylov -lmld_prec -lpsb_prec +MLD_LIBS=-L$(MLDLIBDIR) -lpsb_linsolve -lmld_prec -lpsb_prec FINCLUDES=$(FMFLAG). $(FMFLAG)$(MLDMODDIR) $(FMFLAG)$(MLDINCDIR) $(PSBLAS_INCLUDES) $(FIFLAG). PD3DOBJS=mld_pde3d_newslv.o data_input.o mld_d_tlu_solver.o mld_d_tlu_solver_impl.o From 07149a02ad8ba1c941ac5f157965c5489a4f8c7d Mon Sep 17 00:00:00 2001 From: sfilippone Date: Mon, 11 Nov 2024 09:11:07 +0100 Subject: [PATCH 09/27] Fixes for krylov->linsolve. Test program to be completed. --- cbind/amgprec/amg_dprec_cbind_mod.F90 | 4 ++-- cbind/amgprec/amg_zprec_cbind_mod.F90 | 4 ++-- cbind/test/pargen/Makefile | 16 ++++++------- cbind/test/pargen/amgec.c | 24 +++++++++---------- cbind/test/pargen/runs/{mlde.inp => amge.inp} | 0 5 files changed, 24 insertions(+), 24 deletions(-) rename cbind/test/pargen/runs/{mlde.inp => amge.inp} (100%) diff --git a/cbind/amgprec/amg_dprec_cbind_mod.F90 b/cbind/amgprec/amg_dprec_cbind_mod.F90 index 29c514a9..f6db13c9 100644 --- a/cbind/amgprec/amg_dprec_cbind_mod.F90 +++ b/cbind/amgprec/amg_dprec_cbind_mod.F90 @@ -264,7 +264,7 @@ contains & ah,ph,bh,xh,cdh,options) bind(c) result(res) use psb_base_mod use psb_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_prec_cbind_mod use psb_dkrylov_cbind_mod implicit none @@ -285,7 +285,7 @@ contains & ah,ph,bh,xh,eps,cdh,itmax,iter,err,itrace,irst,istop) bind(c) result(res) use psb_base_mod use psb_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_objhandle_mod use psb_prec_cbind_mod use psb_base_string_cbind_mod diff --git a/cbind/amgprec/amg_zprec_cbind_mod.F90 b/cbind/amgprec/amg_zprec_cbind_mod.F90 index 167509d9..8ae1c964 100644 --- a/cbind/amgprec/amg_zprec_cbind_mod.F90 +++ b/cbind/amgprec/amg_zprec_cbind_mod.F90 @@ -264,7 +264,7 @@ contains & ah,ph,bh,xh,cdh,options) bind(c) result(res) use psb_base_mod use psb_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_prec_cbind_mod use psb_zkrylov_cbind_mod implicit none @@ -285,7 +285,7 @@ contains & ah,ph,bh,xh,eps,cdh,itmax,iter,err,itrace,irst,istop) bind(c) result(res) use psb_base_mod use psb_prec_mod - use psb_krylov_mod + use psb_linsolve_mod use psb_objhandle_mod use psb_prec_cbind_mod use psb_base_string_cbind_mod diff --git a/cbind/test/pargen/Makefile b/cbind/test/pargen/Makefile index 3a2921e8..f5bf13f3 100644 --- a/cbind/test/pargen/Makefile +++ b/cbind/test/pargen/Makefile @@ -9,8 +9,8 @@ HERE=. FINCLUDES=$(FMFLAG). $(FMFLAG)$(LIBDIR) $(FMFLAG)$(PSBLAS_INCDIR) #PSBLAS_LIBS= -L$(PSBLAS_LIBDIR) -L$(LIBDIR) $(CPSBLAS_LIB) $(PSBLAS_LIB) # -lpsb_krylov_cbind -lpsb_prec_cbind -lpsb_base_cbind -PSBC_LIBS= -L$(PSBLAS_LIBDIR) -lpsb_cbind -lpsb_krylov -lpsb_prec -MLDC_LIBS=-L$(LIBDIR) -lmld_cbind -lmld_prec +PSBC_LIBS= -L$(PSBLAS_LIBDIR) -lpsb_cbind -lpsb_linsolve -lpsb_prec +AMGC_LIBS=-L$(LIBDIR) -lamg_cbind -lamg_prec # # Compilers and such # @@ -23,15 +23,15 @@ EXEDIR=./runs #UMFLIBS=-lumfpack -lamd -lcholmod -lcolamd -lcamd -lccolamd -L/usr/include/suitesparse #UMFFLAGS=-DHave_UMF_ -I/usr/include/suitesparse - all: mldec + all: amgec -mldec: mldec.o - $(MPFC) mldec.o -o mldec $(MLDC_LIBS) $(PSBC_LIBS) $(PSBCLDLIBS) $(PSBLAS_LIBS) \ +amgec: amgec.o + $(MPFC) amgec.o -o amgec $(AMGC_LIBS) $(PSBC_LIBS) $(PSBCLDLIBS) $(PSBLAS_LIBS) \ $(UMFLIBS) $(PSBLDLIBS) $(LDLIBS) -lm -lgfortran # \ # -lifcore -lifcoremt -lguide -limf -lirc -lintlc -lcxaguard -L/opt/intel/fc/10.0.023/lib/ -lm - /bin/mv mldec $(EXEDIR) + /bin/mv amgec $(EXEDIR) .f90.o: $(MPFC) $(F90COPT) $(FINCLUDES) $(FDEFINES) -c $< @@ -40,13 +40,13 @@ mldec: mldec.o clean: - /bin/rm -f mldec.o $(EXEDIR)/mldec + /bin/rm -f amgec.o $(EXEDIR)/amgec verycleanlib: (cd ../..; make veryclean) lib: (cd ../../; make library) tests: all - cd runs ; ./mldec < mlde.inp + cd runs ; ./amgec < amge.inp diff --git a/cbind/test/pargen/amgec.c b/cbind/test/pargen/amgec.c index 9a2c42c0..09cf83c7 100644 --- a/cbind/test/pargen/amgec.c +++ b/cbind/test/pargen/amgec.c @@ -77,7 +77,7 @@ #include #include "psb_base_cbind.h" -#include "mld_cbind.h" +#include "amg_cbind.h" double a1(double x, double y, double z) @@ -257,7 +257,7 @@ int main(int argc, char *argv[]) char methd[40], ptype[40], afmt[8]; psb_i_t nparms; psb_i_t idim,info,istop,itmax,itrace,irst,iter,ret; - mld_c_dprec *ph; + amg_c_dprec *ph; psb_c_dspmat *ah; psb_c_dvector *bh, *xh, *rh; psb_i_t nb,nlr, nl; @@ -343,16 +343,16 @@ int main(int argc, char *argv[]) } psb_c_barrier(ictxt); /* Set up the preconditioner */ - ph = mld_c_dprec_new(); - mld_c_dprecinit(ictxt,ph,ptype); - mld_c_dprecseti(ph,"SMOOTHER_SWEEPS",2); - mld_c_dprecseti(ph,"SUB_FILLIN",1); - mld_c_dprecsetc(ph,"COARSE_SOLVE","BJAC"); - mld_c_dprecsetc(ph,"COARSE_SUBSOLVE","ILU"); - mld_c_dprecseti(ph,"COARSE_FILLIN",0); - if ((ret=mld_c_dhierarchy_build(ah,cdh,ph))!=0) + ph = amg_c_dprec_new(); + amg_c_dprecinit(ictxt,ph,ptype); + amg_c_dprecseti(ph,"SMOOTHER_SWEEPS",2); + amg_c_dprecseti(ph,"SUB_FILLIN",1); + amg_c_dprecsetc(ph,"COARSE_SOLVE","BJAC"); + amg_c_dprecsetc(ph,"COARSE_SUBSOLVE","ILU"); + amg_c_dprecseti(ph,"COARSE_FILLIN",0); + if ((ret=amg_c_dhierarchy_build(ah,cdh,ph))!=0) fprintf(stderr,"From hierarchy_build: %d\n",ret); - if ((ret=mld_c_dsmoothers_build(ah,cdh,ph))!=0) + if ((ret=amg_c_dsmoothers_build(ah,cdh,ph))!=0) fprintf(stderr,"From smoothers_build: %d\n",ret); psb_c_barrier(ictxt); @@ -365,7 +365,7 @@ int main(int argc, char *argv[]) options.istop = istop; psb_c_seterraction_ret(); t1=psb_c_wtime(); - ret=mld_c_dkrylov(methd,ah,ph,bh,xh,cdh,&options); + ret=amg_c_dkrylov(methd,ah,ph,bh,xh,cdh,&options); t2=psb_c_wtime(); iter = options.iter; err = options.err; diff --git a/cbind/test/pargen/runs/mlde.inp b/cbind/test/pargen/runs/amge.inp similarity index 100% rename from cbind/test/pargen/runs/mlde.inp rename to cbind/test/pargen/runs/amge.inp From 032543d6253852f60f9928ee01ac7cec6579cb2c Mon Sep 17 00:00:00 2001 From: sfilippone Date: Mon, 11 Nov 2024 13:06:48 +0100 Subject: [PATCH 10/27] Adjusted CBIND test program. --- cbind/test/pargen/amgec.c | 63 ++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/cbind/test/pargen/amgec.c b/cbind/test/pargen/amgec.c index 09cf83c7..329b0649 100644 --- a/cbind/test/pargen/amgec.c +++ b/cbind/test/pargen/amgec.c @@ -123,7 +123,7 @@ double g(double x, double y, double z) #define NBMAX 20 -psb_i_t matgen(psb_i_t ictxt, psb_i_t nl, psb_i_t idim, psb_l_t vl[], +psb_i_t matgen(psb_c_ctxt cctxt, psb_i_t nl, psb_i_t idim, psb_l_t vl[], psb_c_dspmat *ah,psb_c_descriptor *cdh, psb_c_dvector *xh, psb_c_dvector *bh, psb_c_dvector *rh) { @@ -135,7 +135,7 @@ psb_i_t matgen(psb_i_t ictxt, psb_i_t nl, psb_i_t idim, psb_l_t vl[], psb_l_t irow[10*NBMAX], icol[10*NBMAX]; info = 0; - psb_c_info(ictxt,&iam,&np); + psb_c_info(cctxt,&iam,&np); deltah = (double) 1.0/(idim+1); sqdeltah = deltah*deltah; deltah2 = 2.0* deltah; @@ -253,7 +253,8 @@ void get_hparm(FILE *fp, char *val) int main(int argc, char *argv[]) { - psb_i_t ictxt, iam, np; + psb_c_ctxt *cctxt; + psb_i_t iam, np; char methd[40], ptype[40], afmt[8]; psb_i_t nparms; psb_i_t idim,info,istop,itmax,itrace,irst,iter,ret; @@ -269,12 +270,13 @@ int main(int argc, char *argv[]) psb_c_descriptor *cdh; FILE *vectfile; - ictxt = psb_c_init(); - psb_c_info(ictxt,&iam,&np); + cctxt = psb_c_new_ctxt(); + psb_c_init(cctxt); + psb_c_info(*cctxt,&iam,&np); fprintf(stdout,"Initialization: am %d of %d\n",iam,np); fflush(stdout); - psb_c_barrier(ictxt); + psb_c_barrier(*cctxt); if (iam == 0) { get_iparm(stdin,&nparms); get_hparm(stdin,methd); @@ -287,17 +289,17 @@ int main(int argc, char *argv[]) get_iparm(stdin,&irst); } /* Now broadcast the values, and check they're OK */ - psb_c_ibcast(ictxt,1,&nparms,0); - psb_c_hbcast(ictxt,methd,0); - psb_c_hbcast(ictxt,ptype,0); - psb_c_hbcast(ictxt,afmt,0); - psb_c_ibcast(ictxt,1,&idim,0); - psb_c_ibcast(ictxt,1,&istop,0); - psb_c_ibcast(ictxt,1,&itmax,0); - psb_c_ibcast(ictxt,1,&itrace,0); - psb_c_ibcast(ictxt,1,&irst,0); + psb_c_ibcast(*cctxt,1,&nparms,0); + psb_c_hbcast(*cctxt,methd,0); + psb_c_hbcast(*cctxt,ptype,0); + psb_c_hbcast(*cctxt,afmt,0); + psb_c_ibcast(*cctxt,1,&idim,0); + psb_c_ibcast(*cctxt,1,&istop,0); + psb_c_ibcast(*cctxt,1,&itmax,0); + psb_c_ibcast(*cctxt,1,&itrace,0); + psb_c_ibcast(*cctxt,1,&irst,0); - psb_c_barrier(ictxt); + psb_c_barrier(*cctxt); cdh=psb_c_new_descriptor(); psb_c_set_index_base(0); @@ -310,15 +312,15 @@ int main(int argc, char *argv[]) fprintf(stderr,"%d: Input data %d %ld %d %d\n",iam,idim,ng,nb, nl); if ((vl=malloc(nb*sizeof(psb_l_t)))==NULL) { fprintf(stderr,"On %d: malloc failure\n",iam); - psb_c_abort(ictxt); + psb_c_abort(*cctxt); } i = ((psb_l_t)iam) * nb; for (k=0; kdescriptor); @@ -440,6 +442,7 @@ int main(int argc, char *argv[]) if (iam == 0) fprintf(stderr,"program completed successfully\n"); - psb_c_barrier(ictxt); - psb_c_exit(ictxt); + psb_c_barrier(*cctxt); + psb_c_exit(*cctxt); + free(cctxt); } From 053d5c4bc0dbabe6843c6d92b10e846bd9cf20f8 Mon Sep 17 00:00:00 2001 From: sfilippone Date: Mon, 11 Nov 2024 18:10:34 +0100 Subject: [PATCH 11/27] Changed sample input file --- samples/advanced/pdegen/runs/amg_pde3d.inp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/advanced/pdegen/runs/amg_pde3d.inp b/samples/advanced/pdegen/runs/amg_pde3d.inp index d3a7dbda..69db22c0 100644 --- a/samples/advanced/pdegen/runs/amg_pde3d.inp +++ b/samples/advanced/pdegen/runs/amg_pde3d.inp @@ -11,7 +11,7 @@ CG ! Iterative method: 30 ! IRST (restart for RGMRES and BiCGSTABL) 1.d-6 ! EPS %%%%%%%%%%% Main preconditioner choices %%%%%%%%%%%%%%%% -ML-VBM-VCYCLE-FBGS-D-BJAC ! Longer descriptive name for preconditioner (up to 20 chars) +ML-VBM-VCYC-POLY-L1-D-BJAC ! Longer descriptive name for preconditioner (up to 20 chars) ML ! Preconditioner type: NONE JACOBI GS FBGS BJAC AS ML POLY % %%%%%%%%%%% First smoother (for all levels but coarsest) %%%%%%%%%%%%%%%% From 5b654cc2211c83497e67eb5fd269d8360f6d059d Mon Sep 17 00:00:00 2001 From: Fabio Durastante Date: Fri, 15 Nov 2024 17:13:17 +0100 Subject: [PATCH 12/27] Update README.md --- README.md | 91 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 3be67f1f..ee35b6f5 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,75 @@ - AMG4PSBLAS - Algebraic Multigrid Package based on PSBLAS (Parallel Sparse BLAS version 3.8) - -Salvatore Filippone (University of Rome Tor Vergata and IAC-CNR) -Pasqua D'Ambra (IAC-CNR, Naples, IT) -Fabio Durastante (IAC-CNR, Naples, IT) +# AMG4PSBLAS v1.2 +Algebraic Multigrid Package based on [PSBLAS](https://github.com/sfilippone/psblas3) (Parallel Sparse BLAS version 3.9) ---------------------------------------------------------------------- +AMG4PSBLAS is a package of parallel algebraic multilevel preconditioners included in the PSCToolkit (Parallel Sparse Computation Toolkit) software framework. -AMG4PSBLAS is a package of Algebraic MultiGrid (AMG) -preconditioners for the iterative solution of large and sparse linear systems. +It is a progress of a software development project started in 2007, named MLD2P4, which originally implemented a multilevel version of some domain decomposition preconditioners of additive-Schwarz type and was based on a parallel decoupled version of the well known smoothed aggregation method to generate the multilevel hierarchy of coarser matrices. -It is an evolution of MLD2P4 (see LICENSE.MLD2P4), but it has been -thoroughly reworked, and it is sufficiently different to warrant a new -project name. +In the last years the package was extended for including new algorithms and functionalities for the setup and application new AMG preconditioners with the final aims of improving efficiency and scalability when tens of thousands cores are used and of boosting reliability in dealing with general symmetric positive definite linear systems. +It is an evolution of MLD2P4 (see [LICENSE.MLD2P4](LICENSE.MLD2P4)), but due to the significant number of changes and the increase in scope, we decided to rename the package as AMG4PSBLAS. -MAIN REFERENCES: +AMG4PSBLAS has been designed to provide scalable and easy-to-use preconditioners in the context of the PSBLAS (Parallel Sparse Basic Linear Algebra Subprograms) computational framework and can be used in conjuction with the Krylov solvers available in this framework. Our package is based on a completely algebraic approach; therefore users level interfaces assume that the system matrix and preconditioners are represented as PSBLAS distributed sparse matrices. - +AMG4PSBLAS enables the user to easily specify different features of an algebraic multilevel preconditioner, thus allowing to experiment with different preconditioners for the problem and parallel computers at hand. -P. D'Ambra, D. di Serafino, S. Filippone, -MLD2P4: a Package of Parallel Algebraic Multilevel Domain Decomposition -Preconditioners in Fortran 95, -ACM Transactions on Mathematical Software, 37 (3), 2010, art. 30, -doi: 10.1145/1824801.1824808. +The package employs object-oriented design techniques in Fortran 2003, with interfaces to additional third party libraries such as MUMPS, UMFPACK, SuperLU, and SuperLU_Dist, which can be exploited in building multilevel preconditioners. The parallel implementation is based on a Single Program Multiple Data (SPMD) paradigm; the inter-process communication is based on MPI and is managed mainly through PSBLAS. +## Main refrerences: -TO COMPILE +The main reference for features inherited from MLD2P4 is +> P. D'Ambra, D. di Serafino, S. Filippone, +> MLD2P4: a Package of Parallel Algebraic Multilevel Domain Decomposition +> Preconditioners in Fortran 95, +> ACM Transactions on Mathematical Software, 37 (3), 2010, art. 30, +> doi: 10.1145/1824801.1824808. + +The new features introduced and which led to the library's name change are described in the article +> D'Ambra, P., Durastante, F., & Filippone, S. (2021). AMG preconditioners for linear solvers towards extreme scale. SIAM Journal on Scientific Computing, 43(5), S679-S703. + +AMG4PSBLAS contains the suite of preconditioners for the Parallel Sparse Computation Toolkit ([PSCToolkit](https://psctoolkit.github.io/)) suite of libraries. See the paper: +> D’Ambra, P., Durastante, F., & Filippone, S. (2023). Parallel Sparse Computation Toolkit. Software Impacts, 15, 100463. + +## Installing + +Installation requires having a working version of the [PSBLAS](https://github.com/sfilippone/psblas3) library installed. +AMG4PSBLAS has several interfaces to third-party libraries that can be used in the construction and application phases of preconditioners. +In particular, it is possible to link AMG4PSBLAS with the libraries: MUMPS, SuperLU, SuperLU_Dist, UMFPACK. This is _not mandatory_ and the library can run +in isolation and without these features. 0. Unpack the tar file in a directory of your choice (preferrably outside the main PSBLAS directory). -1. run configure --with-psblas= +1. run configure `--with-psblas=` adding the options for MUMPS, SuperLU, SuperLU_Dist, UMFPACK as desired. - See MLD2P4 User's and Reference Guide (Section 3) for details. -2. Tweak Make.inc if you are not satisfied. -3. make; + See [AMG4PSBLAS User's and Reference Guide](docs/amg4psblas_1.0-guide.pdf) (Section 3) for details. +2. Tweak `Make.inc` if you are not satisfied. +3. run `make`; 4. Go into the test subdirectory and build the examples of your choice. -5. (if desired): make install +5. (if desired): `make install` + +>[!CAUTION] +>The single precision version is supported only by MUMPS and SuperLU; +>thus, even if you specify at configure time to use UMFPACK or SuperLU_Dist, +>the corresponding preconditioner options will be available only from +>the double precision version. + +### CUDA, OpeMP, OpenACC + +CUDA, OpenMP and OpenACC features are transparently inherited by PSBLAS installation. If PSBLAS has been configured (and installed) with these supports then AMG4PSBLAS will transparently inherit them. It will then be possible to move the computation to GPU accelerator simply by selecting the appropriate variable types. If these have not been activated or installed for PSBLAS then they will not be available for AMG4PSBLAS either and the operation will be purely on CPU/MPI. + +### EoCoE - Software as service portal +In the European project “Energy oriented Center of Excellence: toward exascale for energy†we made available a software as service portal: [https://eocoe.psnc.pl/](https://eocoe.psnc.pl/). This permits to test several cutting-edge computational methods for accelerating the transition to the production, storage and management of clean, decarbonized energy. Among them you have the possibility of running PSBLAS+AMG4PSBLAS on some test problems to become familiar with using the software. -NOTES +## TODO and bugs + +- [X] Fix all reamining bugs. Bugs? We dont' have any ! 🤓 -- The single precision version is supported only by MUMPS and SuperLU; - thus, even if you specify at configure time to use UMFPACK or SuperLU_Dist, - the corresponding preconditioner options will be available only from - the double precision version. +> [!NOTE] +> To report bugs 🛠or issues â“ please use the [GitHub issue system](https://github.com/sfilippone/amg4psblas/issues). +## The AMG4PSBLAS team. -The AMG4PSBLAS team. ---------------- -Salvatore Filippone -Pasqua D'Ambra -Fabio Durastante +- Salvatore Filippone (University of Rome Tor Vergata and IAC-CNR) +- Pasqua D'Ambra (IAC-CNR, Naples, IT) +- Fabio Durastante (University of Pisa and IAC-CNR, IT) From db9757a45e2b89cf3a9644c8eb0c9ce5fbe76110 Mon Sep 17 00:00:00 2001 From: sfilippone Date: Fri, 15 Nov 2024 17:28:14 +0100 Subject: [PATCH 13/27] Update README Fortran 2003 to 2008 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ee35b6f5..0b5350b0 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ AMG4PSBLAS has been designed to provide scalable and easy-to-use preconditioners AMG4PSBLAS enables the user to easily specify different features of an algebraic multilevel preconditioner, thus allowing to experiment with different preconditioners for the problem and parallel computers at hand. -The package employs object-oriented design techniques in Fortran 2003, with interfaces to additional third party libraries such as MUMPS, UMFPACK, SuperLU, and SuperLU_Dist, which can be exploited in building multilevel preconditioners. The parallel implementation is based on a Single Program Multiple Data (SPMD) paradigm; the inter-process communication is based on MPI and is managed mainly through PSBLAS. +The package employs object-oriented design techniques in Fortran 2008, with interfaces to additional third party libraries such as MUMPS, UMFPACK, SuperLU, and SuperLU_Dist, which can be exploited in building multilevel preconditioners. The parallel implementation is based on a Single Program Multiple Data (SPMD) paradigm; the inter-process communication is based on MPI and is managed mainly through PSBLAS. ## Main refrerences: From 82de529c54f3e31ab52494e6cf14202c4b1a2f36 Mon Sep 17 00:00:00 2001 From: sfilippone Date: Mon, 18 Nov 2024 09:17:11 +0100 Subject: [PATCH 14/27] Makefile in amg4psblas/docs --- docs/Makefile | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs/Makefile diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..6ac24e64 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,7 @@ +all: guide + +guide: + cd src && $(MAKE) clean all + +doxy: + doxygen doxypsb From 70fb39ae55e19e1eea578df451fc796b24efb2c7 Mon Sep 17 00:00:00 2001 From: Fabio Durastante Date: Mon, 18 Nov 2024 10:03:21 +0100 Subject: [PATCH 15/27] Added Polynomial Smoother infos --- .gitignore | 2 + docs/amg4psblas_1.0-guide.pdf | Bin 1831831 -> 1871480 bytes docs/html/index.html | 82 +- docs/html/userhtml.css | 187 +- docs/html/userhtml.html | 82 +- docs/html/userhtmlli1.html | 7 + docs/html/userhtmlli2.html | 78 +- docs/html/userhtmlli3.html | 15 +- docs/html/userhtmlli4.html | 6 +- docs/html/userhtmlli5.html | 99 +- docs/html/userhtmlse1.html | 31 +- docs/html/userhtmlse2.html | 23 +- docs/html/userhtmlse3.html | 24 +- docs/html/userhtmlse4.html | 296 +- docs/html/userhtmlse5.html | 137 +- docs/html/userhtmlse6.html | 129 +- docs/html/userhtmlse7.html | 8 +- docs/html/userhtmlse8.html | 23 +- docs/html/userhtmlse9.html | 86 +- docs/html/userhtmlsu1.html | 90 +- docs/html/userhtmlsu10.html | 149 +- docs/html/userhtmlsu11.html | 260 +- docs/html/userhtmlsu12.html | 261 +- docs/html/userhtmlsu13.html | 292 +- docs/html/userhtmlsu14.html | 67 +- docs/html/userhtmlsu15.html | 173 +- docs/html/userhtmlsu16.html | 436 +-- docs/html/userhtmlsu2.html | 77 +- docs/html/userhtmlsu3.html | 4862 ++++++++++++++------------------- docs/html/userhtmlsu4.html | 10 +- docs/html/userhtmlsu5.html | 50 +- docs/html/userhtmlsu6.html | 73 +- docs/html/userhtmlsu7.html | 46 +- docs/html/userhtmlsu8.html | 89 +- docs/html/userhtmlsu9.html | 2745 +++++++++---------- docs/src/bibliography.tex | 15 +- docs/src/building.tex | 45 +- docs/src/userinterface.tex | 41 +- 38 files changed, 4755 insertions(+), 6341 deletions(-) diff --git a/.gitignore b/.gitignore index 6ecf4e1f..d9e7db98 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ autom4te.cache # the executable from tests runs +# Documentation temporary files +docs/src/userguide.pdf diff --git a/docs/amg4psblas_1.0-guide.pdf b/docs/amg4psblas_1.0-guide.pdf index b3c4f5591380395915c59b64b181301802e9f369..03d93877cb3398af82ede7f10376ed5a4b50efac 100644 GIT binary patch delta 139722 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ⅅ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%0Dg`3Os~yEr6Jb8i8X;R5he4n0 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 delta 107093 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 z z9Xj~&`TW+a7Jk_k^=akF0Uf)?IxRajpB$-A*So0<8gnPQ_hm;lVjl5gM5)L485jJV z9a=UVaC1wafRN*hrY;i2l&h}LTI^&dRsYm-ja7I`89A%%)~@sGhR61o9+uZ?wXk#L zigqPS2Jg6adrYb*Sg*iA_i@nWuTh_l?N56C3$0>SJy`0y@v=b&y-OxXXIr%U&@0BQ z_nq_0N|KH_j?%HN?-(&r`u5V4)vFC<_f9xI+3{%G!ymq@EX6Osn+)D&Qn>CyZQ#3f5=O1T@Q;NULsxQMScBr$)s}ak~7{`dOIr@ z)i-}Ux>jQ6ywbc+qqy;Ib>iQxDft-d+v3=f*c-F#^4^Bqr?~2z=n#Bjvmb?$lqvt4LLCR(TTv$8&|J5 z<2U25P4ea-tvlLjE0(X?*V)4Gm#M~ORZ@0lTJM|+mHnl&Rus0>UgWj=;HX|7j&1Sj zx8T{6uj7(KpKa@MNsIb(g(IUIgapQ(RJonnqEGCTFl(>c1w&1CUzu~rChYyov{%

0pX7?@pw*@$+*Y3P_U(6PR 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 diff --git a/docs/html/index.html b/docs/html/index.html index 876b4291..b5db3f13 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -59,40 +59,33 @@ class="cmr-12">General Overview class="cmr-12">2 Code Distribution -
  Contributors -
  Citing AMG4PSBLAS
3 Configuring and Building AMG4PSBLAS -
  3.1 Prerequisites -
  3.2 Optional third party libraries -
  3.3 Configuration options -
  3.4 Bug reporting -
  3.5 Example and test programs @@ -100,13 +93,11 @@ class="cmr-12">Example and test programs class="cmr-12">4
Getting Started
-
  4.1 Examples -
  4.2 GPU example @@ -114,71 +105,62 @@ class="cmr-12">GPU example class="cmr-12">5
User Interface
-
  5.1 Method init -
  5.2 Method set -
  5.3 Method hierarchy_build -
  5.4 Method smoothers_build -
  5.5 Method build -
  5.6 Method apply -
  5.7 Method free -
  5.8 Method descr -
  5.9 Auxiliary Methods
6 Adding new smoother and solver objects to AMG4PSBLAS
7 Error Handling
A License
B Contributor Covenant Code of Conduct
References diff --git a/docs/html/userhtml.css b/docs/html/userhtml.css index a5ede259..c29347d8 100644 --- a/docs/html/userhtml.css +++ b/docs/html/userhtml.css @@ -22,6 +22,9 @@ .cmmi-8{font-size:72%;font-style: italic;} .cmsy-10x-x-120{font-size:109%;} .cmsy-8{font-size:72%;} +.cmtt-10{font-size:90%;font-family: monospace,monospace;} +.cmtt-10{font-family: monospace,monospace;} +.cmtt-10{font-family: monospace,monospace;} .tctt-1200{font-size:109%;font-family: monospace,monospace;} .cmmi-10x-x-109{font-style: italic;} .cmsy-10x-x-109{} @@ -29,9 +32,6 @@ .cmtt-10x-x-109{font-family: monospace,monospace;} .cmtt-10x-x-109{font-family: monospace,monospace;} .cmcsc-10x-x-109{} -.cmtt-10{font-size:90%;font-family: monospace,monospace;} -.cmtt-10{font-family: monospace,monospace;} -.cmtt-10{font-family: monospace,monospace;} .cmbx-10x-x-109{ font-weight: bold;} .cmbx-10x-x-109{ font-weight: bold;} .cmbx-10x-x-109{ font-weight: bold;} @@ -42,21 +42,26 @@ p.indent{text-indent:0;} p + p{margin-top:1em;} p + div, p + pre {margin-top:1em;} div + p, pre + p {margin-top:1em;} +a { overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; hyphens: auto; } @media print {div.crosslinks {visibility:hidden;}} +table.tabular{border-collapse: collapse; border-spacing: 0;} a img { border-top: 0; border-left: 0; border-right: 0; } center { margin-top:1em; margin-bottom:1em; } td center { margin-top:0em; margin-bottom:0em; } .Canvas { position:relative; } img.math{vertical-align:middle;} +div.par-math-display, div.math-display{text-align:center;} li p.indent { text-indent: 0em } li p:first-child{ margin-top:0em; } li p:last-child, li div:last-child { margin-bottom:0.5em; } +li p:first-child{ margin-bottom:0; } li p~ul:last-child, li p~ol:last-child{ margin-bottom:0.5em; } .enumerate1 {list-style-type:decimal;} .enumerate2 {list-style-type:lower-alpha;} .enumerate3 {list-style-type:lower-roman;} .enumerate4 {list-style-type:upper-alpha;} div.newtheorem { margin-bottom: 2em; margin-top: 2em;} +div.newtheorem .head{font-weight: bold;} .obeylines-h,.obeylines-v {white-space: nowrap; } div.obeylines-v p { margin-top:0; margin-bottom:0; } .overline{ text-decoration:overline; } @@ -82,6 +87,7 @@ div.flushleft {text-align: left;} .framebox-r {text-align:right;} span.thank-mark{ vertical-align: super } span.footnote-mark sup.textsuperscript, span.footnote-mark a sup.textsuperscript{ font-size:80%; } +code.verb{font-family:monospace,monospace;} div.tabular, div.center div.tabular {text-align: center; margin-top:0.5em; margin-bottom:0.5em; } table.tabular td p{margin-top:0em;} table.tabular {margin-left: auto; margin-right: auto;} @@ -100,6 +106,9 @@ table[rules] {border-left:solid black 0.4pt; border-right:solid black 0.4pt; } .hline hr, .cline hr{ height : 0px; margin:0px; } .hline td, .cline td{ padding: 0; } .hline hr, .cline hr{border:none;border-top:1px solid black;} +.hline {border-top: 1px solid black;} +.hline + .vspace:last-child{display:none;} +.hline:first-child{border-bottom:1px solid black;border-top:none;} .tabbing-right {text-align:right;} div.float, div.figure {margin-left: auto; margin-right: auto;} div.float img {text-align:center;} @@ -130,9 +139,9 @@ div.caption span.id{font-weight: bold; white-space: nowrap; } h1.partHead{text-align: center} p.bibitem { text-indent: -2em; margin-left: 2em; margin-top:0.6em; margin-bottom:0.6em; } p.bibitem-p { text-indent: 0em; margin-left: 2em; margin-top:0.6em; margin-bottom:0.6em; } +.subsubsectionHead, .likesubsubsectionHead { font-size: 1em; } .paragraphHead, .likeparagraphHead { margin-top:2em; font-weight: bold;} .subparagraphHead, .likesubparagraphHead { font-weight: bold;} -.quote {margin-bottom:0.25em; margin-top:0.25em; margin-left:1em; margin-right:1em; text-align:justify;} .verse{white-space:nowrap; margin-left:2em} div.maketitle {text-align:center;} h2.titleHead{text-align:center;} @@ -140,121 +149,95 @@ div.maketitle{ margin-bottom: 2em; } div.author, div.date {text-align:center;} div.thanks{text-align:left; margin-left:10%; font-size:85%; font-style:italic; } div.author{white-space: nowrap;} -.quotation {margin-bottom:0.25em; margin-top:0.25em; margin-left:1em; } -.abstract p {margin-left:5%; margin-right:5%;} +div.abstract p {margin-left:5%; margin-right:5%;} div.abstract {width:100%;} -.subsectionToc, .likesubsectionToc {margin-left:2em;} -.subsubsectionToc, .likesubsubsectionToc {margin-left:4em;} +.abstracttitle{text-align:center;margin-bottom:1em;} +.subsectionToc, .likesubsectionToc {margin-left:1em;} +.subsubsectionToc, .likesubsubsectionToc {margin-left:2em;} +.paragraphToc, .likeparagraphToc {margin-left:3em;} +.subparagraphToc, .likesubparagraphToc {margin-left:4em;} .ovalbox { padding-left:3pt; padding-right:3pt; border:solid thin; } .Ovalbox-thick { padding-left:3pt; padding-right:3pt; border:solid thick; } .shadowbox { padding-left:3pt; padding-right:3pt; border:solid thin; border-right:solid thick; border-bottom:solid thick; } .doublebox { padding-left:3pt; padding-right:3pt; border-style:double; border:solid thick; } .rotatebox{display: inline-block;} +code.lstinline{font-family:monospace,monospace;} +pre.listings{font-family: monospace,monospace; white-space: pre-wrap; margin-top:0.5em; margin-bottom:0.5em; } .lstlisting .label{margin-right:0.5em; } -div.lstlisting{font-family: monospace,monospace; white-space: nowrap; margin-top:0.5em; margin-bottom:0.5em; } -div.lstinputlisting{ font-family: monospace,monospace; white-space: nowrap; } +pre.lstlisting{font-family: monospace,monospace; white-space: pre-wrap; margin-top:0.5em; margin-bottom:0.5em; } +pre.lstinputlisting{ font-family: monospace,monospace; white-space: pre-wrap; } .lstinputlisting .label{margin-right:0.5em;} -#TBL-1 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-1{border-collapse:collapse;} -#TBL-1 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-1{border-collapse:collapse;} -#TBL-1 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-1{border-collapse:collapse;} -#TBL-1 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-1{border-collapse:collapse;} -#TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-4{border-collapse:collapse;} -#TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-4{border-collapse:collapse;} -#TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-4{border-collapse:collapse;} -#TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-4{border-collapse:collapse;} -#TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-4{border-collapse:collapse;} -#TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-4{border-collapse:collapse;} -#TBL-5 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-5{border-collapse:collapse;} -#TBL-5 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-5{border-collapse:collapse;} -#TBL-5 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-5{border-collapse:collapse;} -#TBL-5 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-5{border-collapse:collapse;} -#TBL-5 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-5{border-collapse:collapse;} -#TBL-5 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-5{border-collapse:collapse;} +#TBL-1-1{border-left: 1px solid black;} +#TBL-1-1{border-right:1px solid black;} +#TBL-1-2{border-right:1px solid black;} +#TBL-1-3{border-right:1px solid black;} +#TBL-4-1{border-left: 1px solid black;} +#TBL-4-1{border-right:1px solid black;} +#TBL-4-2{border-right:1px solid black;} +#TBL-4-3{border-right:1px solid black;} +#TBL-4-4{border-right:1px solid black;} +#TBL-4-5{border-right:1px solid black;} +#TBL-5-1{border-left: 1px solid black;} +#TBL-5-1{border-right:1px solid black;} +#TBL-5-2{border-right:1px solid black;} +#TBL-5-3{border-right:1px solid black;} +#TBL-5-4{border-right:1px solid black;} +#TBL-5-5{border-right:1px solid black;} td#TBL-5-10-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} +td#TBL-5-10-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} +td#TBL-5-11-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} td#TBL-5-11-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} td#TBL-5-12-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} -#TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-6{border-collapse:collapse;} -#TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-6{border-collapse:collapse;} -#TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-6{border-collapse:collapse;} -#TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-6{border-collapse:collapse;} -#TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-6{border-collapse:collapse;} -#TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-6{border-collapse:collapse;} +td#TBL-5-12-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} +#TBL-6-1{border-left: 1px solid black;} +#TBL-6-1{border-right:1px solid black;} +#TBL-6-2{border-right:1px solid black;} +#TBL-6-3{border-right:1px solid black;} +#TBL-6-4{border-right:1px solid black;} +#TBL-6-5{border-right:1px solid black;} +td#TBL-6-5-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} td#TBL-6-5-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} td#TBL-6-6-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} -#TBL-7 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-7{border-collapse:collapse;} -#TBL-7 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-7{border-collapse:collapse;} -#TBL-7 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-7{border-collapse:collapse;} -#TBL-7 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-7{border-collapse:collapse;} -#TBL-7 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-7{border-collapse:collapse;} -#TBL-7 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-7{border-collapse:collapse;} +td#TBL-6-6-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} +#TBL-7-1{border-left: 1px solid black;} +#TBL-7-1{border-right:1px solid black;} +#TBL-7-2{border-right:1px solid black;} +#TBL-7-3{border-right:1px solid black;} +#TBL-7-4{border-right:1px solid black;} +#TBL-7-5{border-right:1px solid black;} +td#TBL-7-5-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} td#TBL-7-5-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} td#TBL-7-6-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} +td#TBL-7-6-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} +td#TBL-7-7-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} td#TBL-7-7-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} td#TBL-7-12-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} +td#TBL-7-12-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} +td#TBL-7-13-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} td#TBL-7-13-5{border-left:solid black 0.4pt;border-right:solid black 0.4pt;} -#TBL-8 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-8{border-collapse:collapse;} -#TBL-8 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-8{border-collapse:collapse;} -#TBL-8 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-8{border-collapse:collapse;} -#TBL-8 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-8{border-collapse:collapse;} -#TBL-8 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-8{border-collapse:collapse;} -#TBL-8 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-8{border-collapse:collapse;} -#TBL-9 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-9{border-collapse:collapse;} -#TBL-9 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-9{border-collapse:collapse;} -#TBL-9 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-9{border-collapse:collapse;} -#TBL-9 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-9{border-collapse:collapse;} -#TBL-9 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-9{border-collapse:collapse;} -#TBL-9 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-9{border-collapse:collapse;} -#TBL-10 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-10{border-collapse:collapse;} -#TBL-10 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-10{border-collapse:collapse;} -#TBL-10 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-10{border-collapse:collapse;} -#TBL-10 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-10{border-collapse:collapse;} -#TBL-10 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-10{border-collapse:collapse;} -#TBL-10 colgroup{border-left: 1px solid black;border-right:1px solid black;} -#TBL-10{border-collapse:collapse;} +#TBL-8-1{border-left: 1px solid black;} +#TBL-8-1{border-right:1px solid black;} +#TBL-8-2{border-right:1px solid black;} +#TBL-8-3{border-right:1px solid black;} +#TBL-8-4{border-right:1px solid black;} +#TBL-8-5{border-right:1px solid black;} +#TBL-9-1{border-left: 1px solid black;} +#TBL-9-1{border-right:1px solid black;} +#TBL-9-2{border-right:1px solid black;} +#TBL-9-3{border-right:1px solid black;} +#TBL-9-4{border-right:1px solid black;} +#TBL-9-5{border-right:1px solid black;} +#TBL-10-1{border-left: 1px solid black;} +#TBL-10-1{border-right:1px solid black;} +#TBL-10-2{border-right:1px solid black;} +#TBL-10-3{border-right:1px solid black;} +#TBL-10-4{border-right:1px solid black;} +#TBL-10-5{border-right:1px solid black;} +#TBL-11-1{border-left: 1px solid black;} +#TBL-11-1{border-right:1px solid black;} +#TBL-11-2{border-right:1px solid black;} +#TBL-11-3{border-right:1px solid black;} +#TBL-11-4{border-right:1px solid black;} +#TBL-11-5{border-right:1px solid black;} /* end css.sty */ diff --git a/docs/html/userhtml.html b/docs/html/userhtml.html index 876b4291..b5db3f13 100644 --- a/docs/html/userhtml.html +++ b/docs/html/userhtml.html @@ -59,40 +59,33 @@ class="cmr-12">General Overview
class="cmr-12">2
Code Distribution
-
  Contributors -
  Citing AMG4PSBLAS
3 Configuring and Building AMG4PSBLAS -
  3.1 Prerequisites -
  3.2 Optional third party libraries -
  3.3 Configuration options -
  3.4 Bug reporting -
  3.5 Example and test programs @@ -100,13 +93,11 @@ class="cmr-12">Example and test programs class="cmr-12">4
Getting Started
-
  4.1 Examples -
  4.2 GPU example @@ -114,71 +105,62 @@ class="cmr-12">GPU example class="cmr-12">5
User Interface
-
  5.1 Method init -
  5.2 Method set -
  5.3 Method hierarchy_build -
  5.4 Method smoothers_build -
  5.5 Method build -
  5.6 Method apply -
  5.7 Method free -
  5.8 Method descr -
  5.9 Auxiliary Methods
6 Adding new smoother and solver objects to AMG4PSBLAS
7 Error Handling
A License
B Contributor Covenant Code of Conduct
References diff --git a/docs/html/userhtmlli1.html b/docs/html/userhtmlli1.html index dcc83f43..27911345 100644 --- a/docs/html/userhtmlli1.html +++ b/docs/html/userhtmlli1.html @@ -145,6 +145,13 @@ class="cmr-12">of AMG4PSBLAS.
+

+ + + + + +

Contributors

    -
  • +

    Pasqua D’Ambra, IAC-CNR, IT; -

  • -
  • Fabio Durastante, University of Pisa and IAC-CNR, IT;
  • -
  • +

    Fabio Durastante, University of Pisa and IAC-CNR, IT; +

  • +
  • +

    Salvatore Filippone, University of Rome Tor-Vergata and IAC-CNR, IT;

diff --git a/docs/html/userhtmlli4.html b/docs/html/userhtmlli4.html index 2a339025..a943f3f2 100644 --- a/docs/html/userhtmlli4.html +++ b/docs/html/userhtmlli4.html @@ -25,7 +25,7 @@ href="userhtmlse2.html#userhtmlli4.html" >up]

Citing AMG4PSBLAS

When use the library, please cite the following: @@ -41,6 +41,7 @@ class="cmr-12">When use the library, please cite the following:        archivePrefix = {arXiv},        year={2021}      } + @Misc{psctoolkit-web-page,        author = {D’Ambra, Pasqua and Durastante, Fabio and Filippone, Salvatore},        title =  {{PSCToolkit} {W}eb page}, @@ -56,6 +57,9 @@ class="cmr-12">When use the library, please cite the following: + + +

References

@@ -303,22 +303,41 @@ class="cmr-12">  P. D’Ambra, F D’Ambra, F. Durastante, S. Filippone, AMG preconditioners for Linear Solvers towards Extreme Scale, 2020, arXiv:2006.16147v3. +class="cmr-12">, SIAM Journal on Scientific Computing + 43, no. 5 (2021): S679-S703.

[15]   P. D’Ambra, F. Durastante, S. Filippone, S. Massei, S. Thomas + Optimal Polynomial Smoothers for Parallel AMG, 2024, arXiv:2407.09848. +

+

+ [16]   T.)

[16][17]   SIAM Journal on Matrix Analysis and Applications, 20 (3), 1999, 7

[17][18]   Software, 16 (1) 1990, 1–17.

[18][19]   extended set of FORTRAN Basic Linear Algebra Subprograms< class="cmr-12">, ACM Transactions on Mathematical Software, 14 (1) 1988, 1–17. + + +

[19][20]   Clusters, in Proc. of ParCo 2001, Parallel Computing, Advances and Current Issues, 2002. - - -

[20][21]   .

[21][22]    23.

[22][23]   Transactions on Mathematical Software, 26 (4), 2000, 527–55

[23][24]   2016, 23:501-518

[24][25]   , MIT Press, 1998.

[25][26]   Algebra Subprograms for FORTRAN usage, ACM Transactions on Mathematical Software, 5 (3), 1979, 308–323. + + +

[26][27]   J. Lottes, Optimal polynomial smoothers for multigrid V-cycles, + Numerical Linear Algebra with Applications 30.6 (2023): e2518. +

+

+ [28]   Distributed-memory Sparse Direct Solver for Unsymmetric Linear S class="cmr-12">, ACM Transactions on Mathematical Software, 29 (2), 2003, 110–140. - - -

[27][29]   Numerical Linear Algebra with Applications, 15 (5), 2008, 473R

[28][30]   2003.

[29][31]   University Press, 1996.

[30][32]   Press, 1998.

[31][33]    Oosterlee, Multigrid, Academic Press, 2001.

[32][34]   Aggregation Strategies on Massively Parallel Machines, in J. Donnelley, editor, Proceedings of SuperComputing 2000, Dallas, 2000. + + +

[33][35]   (3) 1996, 179–196.

+ + +

Note that the module amg_prec_modNote that the module amg_prec_mod, containing the definition of the preconditioner data type and the interfaces to the routines of AMG4PSBLAS, must be used in any program calling such routines. The modules psb_base_modin any program calling such routines. The modules psb_base_mod, for the sparse matrix and communication descriptor data types, and psb_krylov_modsparse matrix and communication descriptor data types, and psb_krylov_mod, for interfacing with the Krylov solvers, must be also used (see Sectionproblems. However, this does not necessarily correspond to the sh class="cmr-12">on parallel computers.

-  4.1 Examples -
  4.2 GPU example diff --git a/docs/html/userhtmlse5.html b/docs/html/userhtmlse5.html index a7e1fb0e..aa19b30e 100644 --- a/docs/html/userhtmlse5.html +++ b/docs/html/userhtmlse5.html @@ -33,28 +33,20 @@ class="cmr-12">5 User Interface

The basic user interface of AMG4PBLAS consists of eight methods. The six methods -init, set, build, hierarchy_build, smoothers_build and apply init, set, build, hierarchy_build, smoothers_build and apply encapsulate all the functionalities for the setup and the application of any multilevel and one-level preconditioner implemented in the package. The method free preconditioner implemented in the package. The method free deallocates the preconditioner data structure, while descr preconditioner data structure, while descr prints a description of the preconditioner setup by the user. For backward compatibility, methods are also accessible as @@ -67,53 +59,44 @@ class="cmr-12">real/complex and single/double precision data; arguments with app must be passed to the method, i.e.,

+ + +

The new solver object is then dynamically included in the preconditioner structure, to which the preconditioner will conform, even though class="cmr-12">the AMG4PSBLAS library has not been modified to account for this new development. - - -

It is possible to define new values for the keyword WHAT in the set It is possible to define new values for the keyword WHAT in the set routine; if the library code does not recognize a keyword, it passes it down the composition hierarchy @@ -147,8 +113,7 @@ class="cmr-12">any keyword/value pair that does not pertain to a given solver is class="cmr-12">ignored.

An example is provided in the source code distribution under the folder -tests/newslvtests/newslv. In this example we are implementing a new incomplete factorization variant (which is simply the ILU(0) factorization under a new name). Because of the @@ -165,61 +130,51 @@ class="cmr-12">The interfaces for the calls shown above are defined using

-

+

smoother

class(amg_x_base_smoother_type)

+ preconditioner. + style="vertical-align:baseline;" id="TBL-23-3-">

smoother

class(amg_x_base_smoother_type)

The user-defined new smoother to be employed in the -preconditioner.

solver

class(amg_x_base_solver_type)

solver

class(amg_x_base_solver_type)

The user-defined new solver to be employed in the preconditioner.

+ style="vertical-align:baseline;" id="TBL-23-4-">

The user-defined new solver to be employed in the preconditioner.

The other arguments are defined in the way described in Sec. 5.2. As an example, in the -tests/newslv code we define a new object of type amg_d_tlu_solver_typetests/newslv code we define a new object of type amg_d_tlu_solver_type, and we pass it as follows: -

+   
+
   ! sparse matrix and preconditioner
   type(psb_dspmat_type) :: a
   type(amg_dprec_type)  :: prec
   type(amg_d_tlu_solver_type) :: tlusv
+
 ......
   !
   !  prepare the preconditioner: an ML with defaults, but with TLU solver at
@@ -230,6 +185,7 @@ class="cmr-12">pass it as follows:
   nlv = prec%get_nlevs()
   call prec%set(tlusv,   info,ilev=1,ilmax=max(1,nlv-1))
   call prec%smoothers_build(a,desc_a,info)
+
 

@@ -241,6 +197,9 @@ class="cmr-12">pass it as follows: + + +

-
Table 5: Parameters defining the solver at the coarsest level (continued).
@@ -1495,7 +1205,7 @@ class="content">Parameters defining the solver at the coarsest level (continued)
s +class="td11">

BJAC_STOP +

+class="td11">

BJAC_TRACE +

+class="td11">

BJAC_ITRACE +

+class="td11">

BJAC_RESCHECK +

+class="td11">

BJAC_STOPTOL +

+ Minimal Residual method with restarting. + Refer to the PSBLAS guide [21] for further + information. + + for the coarse Krylov solver. + + The same caveat from Table 5 applies here. + +class="td11">

KRM_GLOBAL +

+class="td11">

The stopping tolerance.

+ methods, otherwise it is ignored. + + the relative residual reduction in the 2-norm is + used instead; refer to the PSBLAS [21] guide + for the details. + +class="td11">

KRM_ITMAX +

+ an informational message about convergence + every KRM_ITRACE iterations. If = 0 print a + message in case of convergence failure. + + first fill-in for the approximate inverses. +





what

what

daa type

val

e

val

default

t

coments






BJAC_STOP

character(len=*)

FALSE -

TRUE

FALSE

Select whether to use a stopping criterion for -the Block-Jacobi method used as a coarse -solver.

character(len=*) +

FALSE +

TRUE +

FALSE +

Select whether to use a stopping criterion for + the Block-Jacobi method used as a coarse + solver. +






BJAC_TRACE

character(len=*)

FALSE -

TRUE

FALSE

Select whether to print a trace for the -calculated residual for the Block-Jacobi -method used as a coarse solver.

character(len=*) +

FALSE +

TRUE +

FALSE +

Select whether to print a trace for the + calculated residual for the Block-Jacobi + method used as a coarse solver. +






BJAC_ITRACE

integer

Any integer -

> 0

-1

Number of iterations after which a trace is to -be printed.

integer +

Any integer +

> 0 +

-1 +

Number of iterations after which a trace is to + be printed. +






BJAC_RESCHECK

integer

Any integer -

> 0

-1

Number of iterations after which a residual is -to be calculated.

integer +

Any integer +

> 0 +

-1 +

Number of iterations after which a residual is + to be calculated. +






BJAC_STOPTOL

real(kind_parameter)

Any real -

< 1

0

Tolerance for the stopping criterion on the -residual.

real(kind_parameter) +

Any real +

< 1 +

0 +

Tolerance for the stopping criterion on the + residual. +






KRM_METHOD

character(len=*)

CG -

FCG -

CGS -

CGR -

BICG -

BICGSTAB -

BICGSTABL -

RGMRES

FCG

A string that defines the iterative method to -be used when employing a Krylov method -KRM as a coarse solver.

KRM_METHOD +

character(len=*) +

CG +

FCG +

CGS +

CGR +

BICG +

BICGSTAB +

BICGSTABL +

RGMRES +

FCG +

A string that defines the iterative method to + be used when employing a Krylov method + KRM as a coarse solver. CG the Conjugate -Gradient method; FCG the Flexible Conjugate -Gradient method; CGS the Conjugate Gradient -Stabilized -method; GCR the Generalized Conjugate -Residual method; FCG the Flexible Conjugate -Gradient method; BICG the Bi-Conjugate -Gradient method; BICGSTAB the Bi-Conjugate -Gradient Stabilized method; BICGSTABL the -Bi-Conjugate Gradient Stabilized method -with restarting; RGMRES the Generalized -Minimal Residual method with restarting. -Refer to the PSBLAS guide [20] for further -information.






KRM_KPREC

character(len=*)

Table 1

BJAC

The one-level -preconditioners from the Table 

KRM_KPREC +

character(len=*) +

Table 1 +

BJAC +

The one-level + preconditioners from the Table 1 can be used -for the coarse Krylov solver.






KRM_SUB_SOLVE

character(len=*)

Table 5

ILU

Solver for the diagonal blocks of the coarsest -matrix preconditioner, in case the block Jacobi -solver is chosen -as KRM_KPREC: ILU(

KRM_SUB_SOLVE +

character(len=*) +

Table 5 +

ILU +

Solver for the diagonal blocks of the coarsest + matrix preconditioner, in case the block Jacobi + solver is chosen + as KRM_KPREC: ILU(p), ILU(p,t), MILU(p), -LU from MUMPS, SuperLU or UMFPACK -(plus triangular solve), Approximate Inverses -INVK(p,q), INVT(p11,t2) and AINV(t); -The same caveat from Table 5 applies here.






KRM_GLOBAL

character(len=*)

TRUE, -FALSE

FALSE

Choose between a global Krylov solver, all -unknowns on a single node, or a distributed -one. The default choice is the distributed -solver.

character(len=*) +

TRUE, + FALSE +

FALSE +

Choose between a global Krylov solver, all + unknowns on a single node, or a distributed + one. The default choice is the distributed + solver. +






KRM_EPS

real(kind_parameter)

Real

KRM_EPS

real(kind_parameter)

Real < 1

10

10-6

The stopping tolerance.






KRM_IRST

integer

Integer -

1

30

An integer specifying the restart parameter. -This is employed for the

KRM_IRST +

integer +

Integer +

1 +

30 +

An integer specifying the restart parameter. + This is employed for the BiCGSTABL or RGMRES -methods, otherwise it is ignored.






KRM_ISTOPC

integer

Integers -1,2,3

2

If

KRM_ISTOPC +

integer +

Integers + 1,2,3 +

2 +

If 1 then the method uses the normwise -backward error in the infinity norm; if 2, the -it uses the relative residual in the 2-norm; if 3 -the relative residual reduction in the 2-norm is -used instead; refer to the PSBLAS [20] guide -for the details.






KRM_ITMAX

integer

Integer -

1

40

The maximum number of iterations to -perform.

integer +

Integer +

1 +

40 +

The maximum number of iterations to + perform. +






KRM_ITRACE

integer

Integer -

0

-1

If

KRM_ITRACE +

integer +

Integer +

0 +

-1 +

If > 0 print out -an informational message about convergence -every KRM_ITRACE iterations. If = 0 print a -message in case of convergence failure.






KRM_FILLIN

integer

Integer -

0

0

Fill-in level

KRM_FILLIN +

integer +

Integer +

0 +

0 +

Fill-in level p of the ILU factorizations and -first fill-in for the approximate inverses.






+class="td11">
+ -
Table 6: Additional parameters defining the solver at the coarsest level.
@@ -1946,7 +1571,7 @@ class="content">Additional parameters defining the solver at the coarsest level. >

s +class="cmr-10">-point-Jacobi and Additive + Schwarz, polynomial accelerators; see [15] +

It is ignored by one-level preconditioners. +

+ Note for details on hybrid Gauss-Seidel. + + respectively. Is ignored if the smoother is + POLY + +class="cmr-10">1 + and 30 +





what

what

daa type

val

e

val

default

t

coments






SMOOTHER_TYPE

character(len=*)

JACOBI -

GS -

BGS -

BJAC -

AS -

L1-JACOBI -

L1-BJAC -

L1-FBGS

FBGS

SMOOTHER_TYPE +

character(len=*) +

JACOBI +

GS +

BGS +

BJAC +

AS +

L1-JACOBI +

L1-BJAC +

L1-FBGS +

POLY +

FBGS +

Type of smoother used in the multilevel -preconditioner: point-Jacobi, hybrid -(forward) Gauss-Seidel, hybrid backward -Gauss-Seidel, block-Jacobi, 1-Jacobi, -1–hybrid (forward) Gauss-Seidel, -–hybrid (forward) + Gauss-Seidel, 1-point-Jacobi and Additive Schwarz. -

It is ignored by one-level preconditioners.






SUB_SOLVE

character(len=*)

JACOBI -GS -

BGS -

ILU -

ILUT -

MILU -

MUMPS -

SLU -

UMF -

INVT -

INVK -

AINV

SUB_SOLVE +

character(len=*) +

JACOBI + GS +

BGS +

ILU +

ILUT +

MILU +

MUMPS +

SLU +

UMF +

INVT +

INVK +

AINV +

GS and BGS for pre- -and post-smoothers of -multilevel -preconditioners, -respectively -

ILU for block-Jacobi -and Additive Schwarz -one-level -preconditioners

preconditioners +

The local solver to be used with the -smoother or one-level preconditioner (see -Remark 2, page 24): point-Jacobi, hybrid -(forward) Gauss-Seidel, hybrid backward -Gauss-Seidel, ILU(p), ILU(p,t), MILU(p), -LU from MUMPS, -SuperLU or UMFPACK (plus triangular -solve), Approximate Inverses INVK(p,q), -INVT(p12) and AINV(t); note -that approximate inverses are specifically -suited for GPUs since they do not employ -triangular system solve kernels, see [3]. See -Note for details on hybrid Gauss-Seidel.






SMOOTHER_SWEEPS

integer

SMOOTHER_SWEEPS +

integer +

Any integer -

number 0

1

0 +

1 +

Number of sweeps of the smoother or -one-level preconditioner. In the multilevel -case, no pre-smother or post-smoother -is used if this parameter is set to 0 -together with pos=PRE or pos=POSTtogether with pos=PRE or pos=POST, -respectively.






SUB_OVR

integer

POLY_DEGREE +

integer +

Any integer -

number 0

1

Number of overlap layers, for Additive -Schwarz only.

1 +

Degree of the polynomial accelerator, is + equal to the number of matrix-vector + products performed by the smoother. Is + ignored if the smoother is not POLY +






+class="td11">
Table 7: Parameters defining the smoother or the details of the one-level @@ -2278,7 +1839,7 @@ preconditioner.
-


@@ -2286,9 +1847,9 @@ preconditioner.
-

+

s + + its RAS variant. + + NONEfor its RAS variant. + + factorizations. + + factorization. + + process. + + argument. + + argument. +





what

what

daa type

val

e

val

default

t

coments






SUB_RESTR

character(len=*)

HALO -

NONE

HALO

SUB_OVR +

integer +

Any integer +

number 0 +

1 +

Number of overlap layers, for Additive + Schwarz only. +

SUB_RESTR +

character(len=*) +

HALO +

NONE +

HALO +

Type of restriction operator, for Additive -Schwarz only: HALO for taking into account -the overlap, NONE the overlap, NONE for neglecting it. -

Note that HALO must be chosen for the -classical Addditive Schwarz smoother and -its RAS variant.






SUB_PROL

character(len=*)

SUM -

NONE

NONE

SUB_PROL +

character(len=*) +

SUM +

NONE +

NONE +

Type of prolongation operator, for Additive -Schwarz only: SUM Schwarz only: SUM for adding the -contributions from the overlap, NONE contributions from the overlap, NONE for -neglecting them. -

Note that SUM

Note that SUM must be chosen for the -classical Additive Schwarz smoother, and -NONE for its RAS variant.






SUB_FILLIN

integer

SUB_FILLIN +

integer +

Any integer -

number 0

0

0 +

0 +

Fill-in level p of the incomplete LU -factorizations.






SUB_ILUTHRS

real(kind_parameter)

Any real -

SUB_ILUTHRS +

real(kind_parameter) +

Any real + number 0

0

0 +

0 +

Drop tolerance t in the ILU(p,t) -factorization.






MUMPS_LOC_GLOB

character(len=*)

LOCAL_SOLVER -

GLOBAL_SOLVER

GLOBAL_SOLVER

MUMPS_LOC_GLOB +

character(len=*) +

LOCAL_SOLVER +

GLOBAL_SOLVER +

GLOBAL_SOLVER +

Whether MUMPS should be used as a -distributed solver, or as a serial solver acting -only on the part of the matrix local to each -process.






MUMPS_IPAR_ENTRY

integer

Any integer -number

0

MUMPS_IPAR_ENTRY +

integer +

Any integer + number +

0 +

Set an entry in the MUMPS integer control -array, as chosen via the idx array, as chosen via the idx optional -argument.






MUMPS_RPAR_ENTRY

real

Any real number

0

Set an entry in the MUMPS real control -array, as chosen via the idx

MUMPS_RPAR_ENTRY +

real +

Any real number +

0 +

Set an entry in the MUMPS real control + array, as chosen via the idx optional -argument.






+ style="vertical-align:baseline;" id="TBL-10-10-">
Table 8: Parameters defining the smoother or the details of the one-level preconditioner @@ -2566,6 +2098,219 @@ class="content">Parameters defining the smoother or the details of the one-level +

+ +
+ + + +


+ + + +
+

+

+ + + +





what

data type

val

default

comments






POLY_VARIANT +

character(len=*) +

CHEB_4 +

CHEB_4_OPT +

CHEB_1_OPT +

CHEB_4 +

Select the type of + polynomial accelerator. + The CHEB_4 and + CHEB_4_OPT types + are those based on the + Chebyshev + polynomials of + the 4th-kind described + in [27]. The + CHEB_1_OPT version + is the one described + in [15] and based on + the Chebyshev + polynomials of the + 1st-kind. +






POLY_RHO_ESTIMATE +

character(len=*) +

POLY_RHO_EST_POWER +

POLY_RHO_EST_POWER +

Algorithm for + estimating the spectral + radius of the smoother + to + which the polynomial + acceleration is applied. + The only implemented + algorithm is the power + method; see also the + two following options. +






POLY_RHO_ESTIMATE_ITERATIONS +

integer +

Any integer +

number 1 +

20 +

Number of iterations + for the spectral radius + estimate. +






POLY_RHO_BA +

real(kind_parameter) +

Any real +

number (0,1] +

1 +

Sets an estimate of + the spectral radius of + the base smoother to + which the polynomial + accelerator is applied. +






+
Table 9: Parameters defining the smoother or the details of the one-level preconditioner +(continued).
+ + +

@@ -2574,7 +2319,7 @@ class="content">Parameters defining the smoother or the details of the one-level -