1
+ module custom_solver
2
+ use stdlib_kinds, only: dp
3
+ use stdlib_sparse
4
+ use stdlib_linalg_iterative_solvers, only: linop_dp, solver_workspace_dp, solve_pccg_generic
5
+ implicit none
6
+ contains
7
+ subroutine solve_pccg_custom (A ,b ,x ,di ,tol ,maxiter ,restart ,workspace )
8
+ type (CSR_dp_type), intent (in ) :: A
9
+ real (dp), intent (in ) :: b(:)
10
+ real (dp), intent (inout ) :: x(:)
11
+ real (dp), intent (in ), optional :: tol
12
+ logical (1 ), intent (in ), optional , target :: di(:)
13
+ integer , intent (in ), optional :: maxiter
14
+ logical , intent (in ), optional :: restart
15
+ type (solver_workspace_dp), optional , intent (inout ), target :: workspace
16
+ !- ------------------------
17
+ type (linop_dp) :: op
18
+ type (solver_workspace_dp), pointer :: workspace_
19
+ integer :: n, maxiter_
20
+ real (dp) :: tol_
21
+ logical :: restart_
22
+ logical (1 ), pointer :: di_(:)
23
+ real (dp), allocatable :: diagonal(:)
24
+ !- ------------------------
25
+ n = size (b)
26
+ maxiter_ = n; if (present (maxiter)) maxiter_ = maxiter
27
+ restart_ = .true. ; if (present (restart)) restart_ = restart
28
+ tol_ = 1.e-4_dp ; if (present (tol)) tol_ = tol
29
+
30
+ !- ------------------------
31
+ ! internal memory setup
32
+ op% matvec = > my_matvec
33
+ op% inner_product = > my_dot
34
+ op% preconditionner = > jacobi_preconditionner
35
+ if (present (di))then
36
+ di_ = > di
37
+ else
38
+ allocate (di_(n),source= .false. _1)
39
+ end if
40
+
41
+ if (present (workspace)) then
42
+ if (.not. allocated (workspace_% tmp)) allocate ( workspace_% tmp(n,4 ) )
43
+ workspace_ = > workspace
44
+ else
45
+ allocate ( workspace_ )
46
+ allocate ( workspace_% tmp(n,4 ) , source = 0._dp )
47
+ end if
48
+ call diag(A,diagonal)
49
+ where (abs (diagonal)>epsilon (0.d0 )) diagonal = 1._dp / diagonal
50
+ !- ------------------------
51
+ ! main call to the solver
52
+ call solve_pccg_generic(op,b,x,di_,tol_,maxiter_,restart_,workspace_)
53
+
54
+ !- ------------------------
55
+ ! internal memory cleanup
56
+ if (present (di))then
57
+ di_ = > null ()
58
+ else
59
+ deallocate (di_)
60
+ end if
61
+ if (present (workspace)) then
62
+ workspace_ = > null ()
63
+ else
64
+ deallocate ( workspace_% tmp )
65
+ deallocate ( workspace_ )
66
+ end if
67
+ contains
68
+
69
+ subroutine my_matvec (x ,y )
70
+ real (dp), intent (in ) :: x(:)
71
+ real (dp), intent (inout ) :: y(:)
72
+ call spmv( A , x, y )
73
+ end subroutine
74
+ subroutine jacobi_preconditionner (x ,y )
75
+ real (dp), intent (in ) :: x(:)
76
+ real (dp), intent (inout ) :: y(:)
77
+ y = diagonal * x
78
+ end subroutine
79
+ pure real (dp) function my_dot(x,y) result(r)
80
+ real (dp), intent (in ) :: x(:)
81
+ real (dp), intent (in ) :: y(:)
82
+ r = dot_product (x,y)
83
+ end function
84
+ end subroutine
85
+
86
+ end module custom_solver
87
+
88
+
89
+ program example_solve_custom
90
+ use custom_solver
91
+ implicit none
92
+
93
+ type (CSR_dp_type) :: laplacian_csr
94
+ type (COO_dp_type) :: COO
95
+ real (dp) :: laplacian(5 ,5 )
96
+ real (dp) :: x(5 ), load(5 )
97
+ logical (1 ) :: dirichlet(5 )
98
+
99
+ laplacian = reshape ( [1 , - 1 , 0 , 0 , 0 ,&
100
+ - 1 , 2 , - 1 , 0 , 0 ,&
101
+ 0 , - 1 , 2 , - 1 , 0 ,&
102
+ 0 , 0 , - 1 , 2 , - 1 ,&
103
+ 0 , 0 , 0 , - 1 , 1 ] , [5 ,5 ])
104
+ call dense2coo(laplacian,COO)
105
+ call coo2csr(COO,laplacian_csr)
106
+
107
+ x = 0._dp
108
+ load = dble ( [0 ,0 ,5 ,0 ,0 ] )
109
+
110
+ dirichlet = .false. _1
111
+ dirichlet([1 ,5 ]) = .true. _1
112
+
113
+ call solve_pccg_custom(laplacian_csr, load, x, tol= 1.d-6 , di= dirichlet)
114
+ print * , x ! > solution: [0.0, 2.5, 5.0, 2.5, 0.0]
115
+
116
+ end program example_solve_custom
0 commit comments