~nickpapior/siesta/trunk-buds-format0.92

« back to all changes in this revision

Viewing changes to Src/buds/src/SM_CSR.inc

  • Committer: Nick Papior
  • Date: 2017-04-07 12:42:28 UTC
  • Revision ID: nickpapior@gmail.com-20170407124228-u5t08yr2p4fhzfeo
Initial commit of buds merged into siesta

Currently I have only enabled buds compilation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
  ! @@LICENSE@@ see Copyright notice in the top-directory
 
2
 
 
3
  ! This module may be controlled via these
 
4
  ! preprocessor variables:
 
5
  !  - BUD_MOD_NAME name of the module
 
6
  !  - BUD_TYPE_NAME name of the public type
 
7
  !  - BUD_TYPE_NAME_ name of the internal data pointer
 
8
  !  - BUD_TYPE_NAME_STR the routine name in "string" format (for IO)
 
9
  !
 
10
  ! Additionally the CSR matrix format may be
 
11
  ! controlled via these flags:
 
12
  !  - BUD_SM_CSR
 
13
  !    case ( 0 ) ! default
 
14
  !      standard CSR format (MKL-SpBLAS)
 
15
  !    case ( 1 )
 
16
  !      zero based pointer CSR format
 
17
  !      The row-pointer is zero based
 
18
  !      This will have an additional array with
 
19
  !      the number of non-zero elements per row
 
20
  !        (this is equivalent to the SIESTA sparsity)
 
21
  !      This does not allow C-interoperability (do NOT set
 
22
  !      BUD_SM_INTEROP_C in this case)
 
23
  !
 
24
  !  - BUD_SM_INTEROP_C=0|1
 
25
  !    Use C-indexing with BUD_SM_INTEROP_C == 1
 
26
  !    All subsequent operations correspond to a
 
27
  !    C-index method.
 
28
  !    Cannot be used together with BUD_SM_CSR == 1
 
29
 
 
30
#ifndef BUD_SM_CSR
 
31
# define BUD_SM_CSR 0
 
32
#endif
 
33
 
 
34
  ! Retrieve the settings for the sparse matrix
 
35
# include "SM.inc"
 
36
 
 
37
#if BUD_SM_CSR == 0
 
38
#elif BUD_SM_CSR == 1
 
39
# if BUD_SM_INTEROP_C == 1
 
40
#  error "SM_INTEROP_C may not be defined when using SM_CSR == 1"
 
41
# endif
 
42
#else
 
43
# error "SM_CSR *MUST* be either 0 or 1"
 
44
#endif
 
45
 
 
46
 
 
47
#include "bud_utils.inc"
 
48
 
 
49
  use BUD_CC3(BUD_MOD,_,SM_common)
 
50
 
 
51
  ! This *MUST* be the first statement
 
52
  ! Common parameters and variables used
 
53
# include "bud_common_declarations.inc"
 
54
 
 
55
  !> Sparse matrix type in the CSR format
 
56
  type BUD_TYPE_NAME
 
57
 
 
58
    !> @cond BUD_DEVELOPER
 
59
 
 
60
    !> Stored pointer which contains the reference counting etc.
 
61
    type(BUD_TYPE_NAME_), pointer :: D => null()
 
62
 
 
63
    !> @endcond BUD_DEVELOPER
 
64
 
 
65
#   include "bud_common_type.inc"
 
66
#if BUD_FORTRAN >= 2003
 
67
 
 
68
    !> @name Private procedures
 
69
    !> @{
 
70
    ! Doxygen needed line
 
71
 
 
72
    procedure, private :: new_dim_
 
73
    procedure, private :: new_copy_
 
74
 
 
75
    procedure, private :: column_p_
 
76
    procedure, private :: column_rp_
 
77
 
 
78
    procedure, private :: remove_row_el_
 
79
    procedure, private :: remove_row_list_
 
80
 
 
81
    procedure, private :: remove_col_el_
 
82
    procedure, private :: remove_col_list_
 
83
 
 
84
    procedure, private :: translate_row_el_
 
85
    procedure, private :: translate_row_list_
 
86
 
 
87
    procedure, private :: translate_col_el_
 
88
    procedure, private :: translate_col_list_
 
89
 
 
90
    !> @}
 
91
 
 
92
    !> @iSee #new
 
93
    generic, public :: new => new_dim_, new_copy_
 
94
 
 
95
    !> @iSee #nonzeros
 
96
    procedure, public :: nonzeros => nonzeros_
 
97
 
 
98
    !> @iSee #max_nonzeros
 
99
    procedure, public :: max_nonzeros => max_nonzeros_
 
100
 
 
101
    !> @iSee #rows
 
102
    procedure, public :: rows => rows_
 
103
 
 
104
    !> @iSee #columns
 
105
    procedure, public :: columns => columns_
 
106
 
 
107
    !> @iSee #size
 
108
    procedure, public :: size => size_
 
109
 
 
110
    !> @iSee #index
 
111
    procedure, public :: index => index_
 
112
 
 
113
    !> @iSee #offset_p
 
114
    procedure, public :: offset_p => offset_p_
 
115
 
 
116
    !> @iSee #nrow_p
 
117
    procedure, public :: nrow_p => nrow_p_
 
118
 
 
119
    !> @iSee #column_p
 
120
    generic, public :: column_p => column_p_, column_rp_
 
121
 
 
122
 
 
123
    !> @iSee #add_element
 
124
    procedure, public :: add_element => add_element_
 
125
 
 
126
 
 
127
    !> @iSee #remove_row
 
128
    generic, public :: remove_row => remove_row_el_, &
 
129
      remove_row_list_
 
130
 
 
131
    !> @iSee #remove_column
 
132
    generic, public :: remove_column => remove_col_el_, &
 
133
      remove_col_list_
 
134
 
 
135
    !> @iSee #translate_row
 
136
    generic, public :: translate_row => translate_row_el_, &
 
137
      translate_row_list_
 
138
 
 
139
    !> @iSee #translate_column
 
140
    generic, public :: translate_column => translate_col_el_, &
 
141
      translate_col_list_
 
142
 
 
143
 
 
144
    !> @iSee #sort
 
145
    procedure, public :: sort => sort_
 
146
 
 
147
    !> @iSee #equivalent
 
148
    procedure, public :: equivalent => equivalent_
 
149
 
 
150
    !> @iSee #finalize
 
151
    procedure, public :: finalize => finalize_
 
152
 
 
153
    !> @iSee #attach
 
154
    procedure, public :: attach => attach_
 
155
 
 
156
#endif
 
157
  end type BUD_TYPE_NAME
 
158
 
 
159
 
 
160
  !> @cond BUD_DEVELOPER
 
161
 
 
162
  ! These fields are used in the sparse matrix stuff.
 
163
  integer(BUD_TYPE_VAR_PREC), parameter :: ONE = BUD_CC2(1_,BUD_TYPE_VAR_PREC)
 
164
  integer(BUD_TYPE_VAR_PREC), parameter :: ZERO = BUD_CC2(0_,BUD_TYPE_VAR_PREC)
 
165
 
 
166
  !> @bud container for BUD_TYPE_NAME
 
167
  !!
 
168
  !! Contains the sparsity pattern for a CSR matrix.
 
169
  type BUD_TYPE_NAME_
 
170
 
 
171
    !> Number of rows in the matrix
 
172
    integer(BUD_TYPE_VAR_PREC) :: nr = ZERO
 
173
    !> Number of columns in the matrix
 
174
    integer(BUD_TYPE_VAR_PREC) :: nc = ZERO
 
175
    !> Number of non-zero elements in the sparse matrix
 
176
    integer(BUD_TYPE_VAR_PREC) :: nz = ZERO
 
177
    !> Total number of elements possible in the sparse matrix
 
178
    integer(BUD_TYPE_VAR_PREC) :: nt = ZERO
 
179
 
 
180
    !> Whether the sparse matrix has been sorted, see #sort
 
181
    logical :: sorted = .false.
 
182
 
 
183
    !> Whether the sparse matrix has been finalized, see #finalize
 
184
    logical :: finalized = .false.
 
185
 
 
186
    !> Index of the equivalent row (size `nr+1`)
 
187
    integer(BUD_TYPE_VAR_PREC), allocatable :: rptr(:)
 
188
 
 
189
    !> Number of non-zero elements per row
 
190
    integer(BUD_TYPE_VAR_PREC), allocatable :: nrow(:)
 
191
 
 
192
    !> The column index of the equivalent sparse matrix (size `nz`)
 
193
    integer(BUD_TYPE_VAR_PREC), allocatable :: col(:)
 
194
 
 
195
 
 
196
    ! Consistent data in the reference counted object
 
197
#   include "bud_common_type_.inc"
 
198
 
 
199
  end type BUD_TYPE_NAME_
 
200
 
 
201
  !> @endcond BUD_DEVELOPER
 
202
 
 
203
 
 
204
  !> Create a new sparse matrix
 
205
  !!
 
206
  !! You may either create an empty sparse matrix with
 
207
  !! a fixed size, or create a sparse matrix from
 
208
  !! existing data.
 
209
  interface new
 
210
    module procedure new_dim_
 
211
    module procedure new_copy_
 
212
  end interface
 
213
  public :: new
 
214
 
 
215
 
 
216
  !> Retrieve a pointer to the row offsets/pointers
 
217
  !!
 
218
  !! A pointer with the row offsets.
 
219
  !!
 
220
#if BUD_SM_CSR == 0
 
221
# if BUD_SM_INTEROP_C == 0
 
222
  !! `M(ir,col(pointer(ir)))`
 
223
# else
 
224
  !! `M(ir,col(pointer(ir)+1))`
 
225
# endif
 
226
  !! is the first sparse element in row `ir`.
 
227
#elif BUD_SM_CSR == 1
 
228
  !! `M(ir,col(pointer(ir)+1))` is the first sparse
 
229
  !! element in row `ir`.
 
230
#endif
 
231
  interface offset_p
 
232
    module procedure offset_p_
 
233
  end interface
 
234
  public :: offset_p
 
235
 
 
236
 
 
237
  !> Retrieve a pointer to the column indices
 
238
  interface column_p
 
239
    module procedure column_p_
 
240
    module procedure column_rp_
 
241
  end interface
 
242
  public :: column_p
 
243
 
 
244
  !> Retrieve a pointer to the number of entries per row
 
245
  interface nrow_p
 
246
    module procedure nrow_p_
 
247
  end interface
 
248
  public :: nrow_p
 
249
 
 
250
  !> Retrieve the sparse index for the row and column (-1 if non existing)
 
251
  interface index
 
252
    module procedure index_
 
253
  end interface
 
254
  public :: index
 
255
 
 
256
 
 
257
  !> Remove rows from the sparse matrix
 
258
  interface remove_row
 
259
    module procedure remove_row_el_
 
260
    module procedure remove_row_list_
 
261
  end interface
 
262
  public :: remove_row
 
263
 
 
264
  !> Remove columns from the sparse matrix
 
265
  interface remove_column
 
266
    module procedure remove_col_el_
 
267
    module procedure remove_col_list_
 
268
  end interface
 
269
  public :: remove_column
 
270
 
 
271
 
 
272
  !> Translate rows in the sparse matrix to new rows
 
273
  !!
 
274
  !! This will essentially change all entries for given
 
275
  !! rows into a new set of rows.
 
276
  !! Furthermore, by denoting the new row with a negative
 
277
  !! index the element will be deleted.
 
278
  interface translate_row
 
279
    module procedure translate_row_el_
 
280
    module procedure translate_row_list_
 
281
  end interface
 
282
  public :: translate_row
 
283
 
 
284
 
 
285
  !> Translate columns in the sparse matrix to new columns
 
286
  !!
 
287
  !! This will essentially change all entries for given
 
288
  !! columns into a new set of columns.
 
289
  !! Furthermore, by denoting the new column with a negative
 
290
  !! index the column will be deleted.
 
291
  interface translate_column
 
292
    module procedure translate_col_el_
 
293
    module procedure translate_col_list_
 
294
  end interface
 
295
  public :: translate_column
 
296
 
 
297
 
 
298
  !> Sorts columns in the sparse matrix
 
299
  !!
 
300
  !! Sorts the sparse matrix such that the column
 
301
  !! index is always increasing for each row.
 
302
  !! This will generally allow faster access patterns.
 
303
  !!
 
304
  !! One may query the error of the object to check
 
305
  !! whether the input is correct.
 
306
  interface sort
 
307
    module procedure sort_
 
308
  end interface
 
309
  public :: sort
 
310
 
 
311
 
 
312
  !> Checks whether two sparse matrices have the same elements
 
313
  !!
 
314
  !! This routine returns `.true.` if the two
 
315
  !! sparse matrices have all the same elements in the
 
316
  !! same order.
 
317
  !!
 
318
  !! In case it is the same object it returns immediately
 
319
  !! with `.true.`.
 
320
  interface equivalent
 
321
    module procedure equivalent_
 
322
  end interface
 
323
  public :: equivalent
 
324
 
 
325
 
 
326
  !> Finalize the sparsity pattern by removing non-used elements
 
327
  !!
 
328
  !! After finalization the number of non-zero elements
 
329
  !! and the total number of possible elements are the same.
 
330
  !! I.e. this routine removes all non-used elements in the
 
331
  !! sparse matrix.
 
332
  !!
 
333
  !! @note this routine re-creates the sparse matrix,
 
334
  !! so any pointers to the internal data-structure
 
335
  !! must be re-instantiated before use.
 
336
  interface finalize
 
337
    module procedure finalize_
 
338
  end interface
 
339
  public :: finalize
 
340
 
 
341
 
 
342
  !> Adds a non-zero element to the sparse matrix
 
343
  !!
 
344
  !! Add a non-zero element to the sparse matrix.
 
345
  !! In case there is not enough space the sparse matrix
 
346
  !! will be re-allocated and copied to it-self.
 
347
  !! Adding an element will thus not necessarily preserve
 
348
  !! the allocated elements and any pointers to the
 
349
  !! data contained needs to be updated.
 
350
  !!
 
351
  !! If the error is `0` there was no need to
 
352
  !! extend the sparse matrix data.
 
353
  !! If the error is `-1` the element has not been added
 
354
  !! If the error is above `0` the sparse matrix
 
355
  !! has been re-allocated and the element is contained.
 
356
  !! The re-allocation ensures that all rows can
 
357
  !! contain `maxval(nrow)+8` and can thus result in
 
358
  !! a large memory increase.
 
359
  interface add_element
 
360
    module procedure add_element_
 
361
  end interface
 
362
  public :: add_element
 
363
 
 
364
 
 
365
  ! Include the common elements of a sparsity method
 
366
  ! This includes "bud_common.inc"
 
367
# include "SM_common.inc"
 
368
 
 
369
 
 
370
  !> @cond BUD_DEVELOPER
 
371
 
 
372
  !> Internal routine for cleaning up the data container.
 
373
  !!
 
374
  !! @dev_note
 
375
  !! This routine is only used internally to clean-up
 
376
  !! any data in the type.
 
377
  !! Should never be made public.
 
378
  subroutine delete_(this)
 
379
    type(BUD_TYPE_NAME), intent(inout) :: this
 
380
    integer :: stat, istat
 
381
 
 
382
    this%D%nr = 0
 
383
    this%D%nc = 0
 
384
    this%D%nz = 0
 
385
    this%D%nt = 0
 
386
    this%D%sorted = .false.
 
387
    this%D%finalized = .false.
 
388
 
 
389
    ! Currently we do not allow external memory
 
390
    ! tracking.
 
391
    if ( .not. allocated(this%D%col) ) return
 
392
    stat = 0
 
393
    deallocate(this%D%rptr, stat=istat)
 
394
    if ( 0 /= istat ) stat = istat
 
395
    deallocate(this%D%col, stat=stat)
 
396
    if ( 0 /= istat ) stat = istat
 
397
    deallocate(this%D%nrow, stat=stat)
 
398
    if ( 0 /= istat ) stat = istat
 
399
 
 
400
  end subroutine delete_
 
401
 
 
402
  !> @endcond BUD_DEVELOPER
 
403
 
 
404
 
 
405
  !> @param[in] from the original `bud` which is copied to `to`
 
406
  !! @param[inout] to the output `bud` with the full copied data
 
407
  !! @param[in] dealloc @opt=.true. whether `to` should be de-allocated before
 
408
  subroutine copy_(from, to, dealloc)
 
409
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: from
 
410
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: to
 
411
    logical, intent(in), optional :: dealloc
 
412
    logical :: ldealloc
 
413
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: fptr(:), nrow(:), fcol(:)
 
414
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: tptr(:)
 
415
    integer(BUD_TYPE_VAR_PREC) :: i, ir, nr
 
416
 
 
417
    call set_error(to, 0)
 
418
 
 
419
    ! Check options
 
420
    ldealloc = .true.
 
421
    if ( present(dealloc) ) ldealloc = dealloc
 
422
    if ( ldealloc ) call delete(to)
 
423
 
 
424
    ! quick return if there is nothing to copy
 
425
    if ( .not. is_initd(from) ) return
 
426
 
 
427
    if ( is_initd(to) ) then
 
428
 
 
429
      ! Check if to has room
 
430
      if ( rows(from) /= rows(to) .or. &
 
431
        columns(from) /= columns(to) ) then
 
432
 
 
433
        ! We do not have the same shape
 
434
        call set_error(to, -1)
 
435
        return
 
436
 
 
437
      end if
 
438
 
 
439
      ! They have the same dimensions
 
440
      ! Check there is room
 
441
      call attach(from, nr=nr, rptr=fptr, nrow=nrow, col=fcol)
 
442
      call attach(to, rptr=tptr)
 
443
 
 
444
      do ir = 1 , nr
 
445
 
 
446
        if ( nrow(ir) > tptr(ir+ONE) - tptr(ir) ) then
 
447
          call set_error(to, ir)
 
448
          exit
 
449
        end if
 
450
 
 
451
      end do
 
452
 
 
453
      ! quick return if there is not room
 
454
      ! The error message will return the column
 
455
      ! where there is not enough room
 
456
      if ( error(to) /= 0 ) return
 
457
 
 
458
      ! Now reset all elements in `to`
 
459
      call attach(to, nrow=nrow)
 
460
 
 
461
      ! reset everything
 
462
      nrow(:) = 0
 
463
 
 
464
      ! Loop all elements in from and copy them to
 
465
      to%D%sorted = .true.
 
466
      do ir = 1, nr
 
467
 
 
468
        fcol => column_p(from, ir)
 
469
 
 
470
        do i = 1, size(fcol)
 
471
          call add_element(to, ir, fcol(i))
 
472
        end do
 
473
 
 
474
      end do
 
475
 
 
476
    else
 
477
 
 
478
      ! We make a copy by creating it
 
479
      call new(to, from%D%nr, from%D%nc, from%D%nz, &
 
480
        from%D%rptr, from%D%col, from%D%nrow)
 
481
      to%D%sorted = from%D%sorted
 
482
 
 
483
    end if
 
484
 
 
485
  end subroutine copy_
 
486
 
 
487
  !> @param[inout] this the sparse matrix
 
488
  !! @param[in] nr number of rows of the matrix
 
489
  !! @param[in] nc number of columns of the matrix
 
490
  !! @param[in] nt @opt total number of possible non-zero elements
 
491
  !! @param[in] npr @opt number of non-zero elements per row (defaults to 10 if `nt` is not specified)
 
492
  subroutine new_dim_(this, nr, nc, nt, npr)
 
493
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
494
    integer(BUD_TYPE_VAR_PREC), intent(in) :: nr, nc
 
495
    integer(BUD_TYPE_VAR_PREC), intent(in), optional :: nt, npr
 
496
    integer(BUD_TYPE_VAR_PREC) :: r
 
497
 
 
498
    call initialize(this)
 
499
 
 
500
    this%D%nr = nr
 
501
    this%D%nc = nc
 
502
    if ( present(nt) ) then
 
503
      this%D%nt = nt
 
504
    else if ( present(npr) ) then
 
505
      this%D%nt = npr * nr
 
506
    else
 
507
      this%D%nt = nr * BUD_CC2(10_,BUD_TYPE_VAR_PREC)
 
508
    end if
 
509
    this%D%nz = 0
 
510
    this%D%sorted = .false.
 
511
    this%D%finalized = .false.
 
512
 
 
513
    allocate(this%D%rptr(nr+1))
 
514
    allocate(this%D%nrow(nr))
 
515
    allocate(this%D%col(this%D%nt))
 
516
 
 
517
    ! Initialize sparse matrix
 
518
    if ( present(npr) ) then
 
519
      this%D%rptr(1) = BUD_SM_PTR
 
520
      do r = 1 , nr
 
521
        this%D%rptr(r) = this%D%rptr(r-ONE) + npr
 
522
      end do
 
523
      this%D%rptr(nr+1) = this%D%nt + BUD_SM_PTR
 
524
    else
 
525
      this%D%rptr(1) = BUD_SM_PTR
 
526
    end if
 
527
    do r = 1 , nr
 
528
      this%D%nrow(r) = ZERO
 
529
    end do
 
530
 
 
531
  end subroutine new_dim_
 
532
 
 
533
 
 
534
  !> @param[inout] this the new sparse matrix
 
535
  !! @param[in] nr number of rows of the matrix
 
536
  !! @param[in] nc number of columns of the matrix
 
537
  !! @param[in] nz number of non-zero elements of the matrix
 
538
  !! @param[in] rptr row pointers (at least size `nr`)
 
539
  !! @param[in] col column indices for the sparse elements
 
540
  !! @param[in] nrow @opt number of column elements per row
 
541
  subroutine new_copy_(this, nr, nc, nz, rptr, col, nrow)
 
542
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
543
    ! sizes
 
544
    integer(BUD_TYPE_VAR_PREC), intent(in) :: nr, nc, nz
 
545
    ! limiting ptr
 
546
    integer(BUD_TYPE_VAR_PREC), intent(in) :: rptr(nr), col(nz)
 
547
    integer(BUD_TYPE_VAR_PREC), intent(in), optional :: nrow(nr)
 
548
 
 
549
    integer(BUD_TYPE_VAR_PREC) :: r
 
550
 
 
551
    ! Copy over information
 
552
    ! It must be based on the starting index
 
553
    if ( rptr(1) /= BUD_SM_PTR ) then
 
554
      call delete(this)
 
555
      return
 
556
    end if
 
557
 
 
558
    ! pre-allocate
 
559
    call new(this, nr, nc, nz)
 
560
    this%D%nz = nz
 
561
 
 
562
    ! Copy pointers
 
563
    do r = 1 , nr
 
564
      this%D%rptr(r) = rptr(r)
 
565
    end do
 
566
 
 
567
    ! create last pointer (to one plus number of elements)
 
568
    ! This ensures simple loops without taking care of
 
569
    ! the last index
 
570
    this%D%rptr(this%D%nr+1) = this%D%nz + BUD_SM_PTR
 
571
 
 
572
    if ( present(nrow) ) then
 
573
      do r = 1 , nr
 
574
        this%D%nrow(r) = nrow(r)
 
575
      end do
 
576
    else
 
577
      do r = 1 , nr
 
578
        this%D%nrow(r) = this%D%rptr(r+1) - this%D%rptr(r)
 
579
      end do
 
580
    end if
 
581
 
 
582
    do r = 1 , nz
 
583
      this%D%col(r) = col(r)
 
584
    end do
 
585
 
 
586
  end subroutine new_copy_
 
587
 
 
588
 
 
589
  !> @param[in] this sparse matrix
 
590
  !! @return a pointer to the row offsets for the sparse matrix (contiguous)
 
591
  function offset_p_(this) result(rptr)
 
592
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
593
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: rptr(:)
 
594
 
 
595
    rptr => this%D%rptr
 
596
 
 
597
  end function offset_p_
 
598
 
 
599
  !> @param[in] this sparse matrix
 
600
  !! @return a pointer to the column indices for the sparse matrix (contiguous)
 
601
  function column_p_(this) result(col)
 
602
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
603
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: col(:)
 
604
 
 
605
    col => this%D%col
 
606
 
 
607
  end function column_p_
 
608
 
 
609
  !> @param[in] this sparse matrix
 
610
  !> @param[in] r only retrieve the columns that reside in row `r`
 
611
  !! @return a pointer to the column indices for the sparse matrix of row `r` (contiguous)
 
612
  function column_rp_(this, r) result(col)
 
613
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
614
    integer(BUD_TYPE_VAR_PREC), intent(in) :: r
 
615
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: col(:)
 
616
 
 
617
    col => this%D%col(this%D%rptr(r)BUD_SM_PTR_A:this%D%rptr(r)+this%D%nrow(r)BUD_SM_PTR_B)
 
618
 
 
619
  end function column_rp_
 
620
 
 
621
  !> @param[in] this sparse matrix
 
622
  !! @return a pointer to the array that holds the number of entries per row
 
623
  function nrow_p_(this) result(nrow)
 
624
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
625
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: nrow(:)
 
626
 
 
627
    nrow => this%D%nrow
 
628
 
 
629
  end function nrow_p_
 
630
 
 
631
 
 
632
  !> @param[in] this sparse matrix @bud
 
633
  !! @param[out] nr @opt number of rows in SM
 
634
  !! @param[out] nc @opt number of columns in SM
 
635
  !! @param[out] nz @opt number of non-zero elements in SM
 
636
  !! @param[out] nt @opt total number of possible non-zero elements in SM
 
637
  !! @param[out] rptr @opt row pointer (`rptr(2)BUD_SM_PTR_A` is starting index of `ir=2`)
 
638
  !! @param[out] nrow @opt number of non-zero elements per row
 
639
  subroutine attach_(this, D, nr, nc, nz, nt, rptr, col, nrow)
 
640
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
641
    ! Having this forces the user to explicitly specify the
 
642
    ! wanted information.
 
643
    logical, intent(in), optional :: D
 
644
    integer(BUD_TYPE_VAR_PREC), intent(out), optional :: nr, nc, nz, nt
 
645
    integer(BUD_TYPE_VAR_PREC), intent(out), pointer BUD_FORTRAN_CONTIGUOUS, optional :: rptr(:), col(:)
 
646
    integer(BUD_TYPE_VAR_PREC), intent(out), pointer BUD_FORTRAN_CONTIGUOUS, optional :: nrow(:)
 
647
 
 
648
    if ( is_initd(this) ) then
 
649
      if ( present(nr) ) nr = this%D%nr
 
650
      if ( present(nc) ) nc = this%D%nc
 
651
      if ( present(nz) ) nz = this%D%nz
 
652
      if ( present(nt) ) nt = this%D%nt
 
653
      if ( present(rptr) ) rptr => this%D%rptr
 
654
      if ( present(col) ) col => this%D%col
 
655
      if ( present(nrow) ) nrow => this%D%nrow
 
656
    else
 
657
      if ( present(nr) ) nr = ZERO
 
658
      if ( present(nc) ) nc = ZERO
 
659
      if ( present(nz) ) nz = ZERO
 
660
      if ( present(nt) ) nt = ZERO
 
661
      if ( present(rptr) ) nullify(rptr)
 
662
      if ( present(col) ) nullify(col)
 
663
      if ( present(nrow) ) nullify(nrow)
 
664
    end if
 
665
 
 
666
  end subroutine attach_
 
667
 
 
668
 
 
669
  !> @param[in] this the sparse matrix (sorted, @isee #sp_sort)
 
670
#if BUD_SM_CSR == 0 && BUD_SM_INTEROP_C == 1
 
671
  !! @param[in] ir row index (0-based)
 
672
  !! @param[in] ic column index (0-based)
 
673
  !! @return the sparse index of `M(ir,ic)`, `<0` if `M(ir,ic) = 0` (0-based)
 
674
#else
 
675
  !! @param[in] ir row index (1-based)
 
676
  !! @param[in] ic column index (1-based)
 
677
  !! @return the sparse index of `M(ir,ic)`, `<0` if `M(ir,ic) = 0` (1-based)
 
678
#endif
 
679
  pure function index_(this, ir, ic) result(idx)
 
680
    use BUD_CC2(BUD_MOD, _utils), only: find_bin
 
681
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
682
    integer(BUD_TYPE_VAR_PREC), intent(in) :: ir
 
683
    integer(BUD_TYPE_VAR_PREC), intent(in) :: ic
 
684
    integer(BUD_TYPE_VAR_PREC) :: idx
 
685
 
 
686
    if ( .not. this%D%sorted ) then
 
687
 
 
688
      do idx = this%D%rptr(ir) BUD_SM_PTR_A , this%D%rptr(ir) + this%D%nrow(ir) BUD_SM_PTR_B
 
689
        if ( this%D%col(idx) == ic ) return
 
690
      end do
 
691
 
 
692
      idx = - ONE
 
693
 
 
694
      return
 
695
 
 
696
    end if
 
697
 
 
698
    call find_bin(this%D%nrow(ir), &
 
699
      this%D%col(this%D%rptr(ir) BUD_SM_PTR_A:), ic, idx)
 
700
    if ( idx > ZERO ) idx = this%D%rptr(ir) BUD_SM_PTR_B + idx
 
701
 
 
702
  end function index_
 
703
 
 
704
 
 
705
 
 
706
  !> @param[inout] this sparse matrix to sort (in-place)
 
707
  !! @param[out] pvt @opt=@none if requested the pivoting array for the sorted sparsity pattern
 
708
  subroutine sort_(this, pvt)
 
709
    ! We use the quick-sort algorithm in this general finalization
 
710
    ! algorithm.
 
711
    use BUD_CC2(BUD_MOD, _utils), only: sort_quick
 
712
 
 
713
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
714
    integer(BUD_TYPE_VAR_PREC), intent(out), target, optional :: pvt(:)
 
715
 
 
716
    ! Local variables
 
717
    integer(BUD_TYPE_VAR_PREC) :: ir, nr, nz, ptr, i
 
718
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: rptr(:), nrow(:), col(:), tvt(:)
 
719
 
 
720
    ! Initialize error
 
721
    call set_error(this, 0)
 
722
 
 
723
    ! Get sparse matrix array
 
724
    call attach(this, nr=nr, nz=nz, rptr=rptr, col=col, nrow=nrow)
 
725
 
 
726
    if ( present(pvt) ) then
 
727
 
 
728
      if ( size(pvt) < nz ) then
 
729
        call set_error(this, SM_INPUT + 3)
 
730
        pvt = -ONE
 
731
        return
 
732
      end if
 
733
 
 
734
      do ir = 1 , nr
 
735
 
 
736
        nz = nrow(ir)
 
737
        ptr = rptr(ir) - BUD_SM_PTR
 
738
 
 
739
        ! get pivoting array
 
740
        tvt => pvt(ptr+1:)
 
741
 
 
742
        call sort_quick(nz, col(ptr+1:), tvt)
 
743
        do i = 1 , nz
 
744
          tvt(i) = ptr + tvt(i)
 
745
        end do
 
746
        do i = 1 , nz
 
747
          col(ptr + i) = col(tvt(i))
 
748
        end do
 
749
 
 
750
      end do
 
751
 
 
752
    else
 
753
 
 
754
      do ir = 1 , nr
 
755
 
 
756
        col => column_p(this, ir)
 
757
        nz = size(col)
 
758
 
 
759
        call sort_quick(nz, col(1:))
 
760
 
 
761
      end do
 
762
 
 
763
    end if
 
764
 
 
765
    this%D%sorted = .true.
 
766
 
 
767
  end subroutine sort_
 
768
 
 
769
 
 
770
  !> @param[inout] a first sparse matrix
 
771
  !! @param[inout] b second sparse matrix
 
772
  !! @return whether they have the same entries
 
773
  function equivalent_(a, b) result(is)
 
774
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: a, b
 
775
    logical :: is
 
776
 
 
777
    integer(BUD_TYPE_VAR_PREC) :: i, nr
 
778
 
 
779
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: arow(:), acol(:)
 
780
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: brow(:), bcol(:)
 
781
 
 
782
    is = .true.
 
783
    if ( same(a, b) ) return
 
784
 
 
785
    is = rows(a) == rows(b) .and. &
 
786
      columns(a) == columns(b)
 
787
    if ( .not. is ) return
 
788
 
 
789
    ! get information
 
790
    call attach(a, nr=nr, nrow=arow)
 
791
    call attach(b, nrow=brow)
 
792
 
 
793
    do i = 1, nr
 
794
 
 
795
      ! Check number of elements per row
 
796
      is = arow(i) == brow(i)
 
797
      if ( .not. is ) return
 
798
 
 
799
      ! check that there are elements
 
800
      if ( arow(i) == 0 ) cycle
 
801
 
 
802
      acol => column_p(a, i)
 
803
      bcol => column_p(b, i)
 
804
 
 
805
      is = all(acol == bcol)
 
806
      if ( .not. is ) return
 
807
 
 
808
    end do
 
809
 
 
810
  end function equivalent_
 
811
 
 
812
 
 
813
  !> @param[inout] this sparse matrix to finalize (in-place)
 
814
  subroutine finalize_(this)
 
815
    use BUD_CC3(BUD_MOD,_,BUD_LIST_NAME)
 
816
 
 
817
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
818
 
 
819
    ! Local variables
 
820
    integer(BUD_TYPE_VAR_PREC) :: ir, nr, nc, nz
 
821
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: rptr(:), col(:)
 
822
 
 
823
    type(BUD_LIST_NAME) :: lptr, lcol
 
824
    integer(BUD_TYPE_VAR_PREC) :: p
 
825
    logical :: sorted
 
826
 
 
827
    ! Initialize error
 
828
    call set_error(this, 0)
 
829
 
 
830
    ! Get sparse matrix array
 
831
    call attach(this, nr=nr, nc=nc, nz=nz, col=col)
 
832
 
 
833
    ! initialize lists
 
834
    call new(lptr, nr)
 
835
    call new(lcol, nz)
 
836
 
 
837
    ! Initialize the pointer
 
838
    p = BUD_SM_PTR
 
839
    call push(lptr, p)
 
840
 
 
841
    do ir = 1 , nr
 
842
 
 
843
      col => column_p(this, ir)
 
844
      nz = size(col)
 
845
 
 
846
      ! Push the new pointer index
 
847
      p = p + nz
 
848
      call push(lptr, p)
 
849
 
 
850
      ! Push the column-indices to the list
 
851
      call push(lcol, nz, col)
 
852
 
 
853
    end do
 
854
 
 
855
    ! Determine whether we should sort it after-wards
 
856
    ! I.e. maintain state of object
 
857
    sorted = is_sorted(this)
 
858
 
 
859
    p = size(lcol)
 
860
    ! Get pointers
 
861
    rptr => list_p(lptr)
 
862
    col => list_p(lcol)
 
863
    call new(this, nr, nc, p, rptr, col)
 
864
    call delete(lptr)
 
865
    call delete(lcol)
 
866
 
 
867
    if ( sorted ) then
 
868
      call sort(this)
 
869
    end if
 
870
    this%D%finalized = .true.
 
871
 
 
872
  end subroutine finalize_
 
873
 
 
874
 
 
875
  !> @param[inout] this the sparse matrix to add an element to
 
876
  !! @param[in] ir the row index of the element
 
877
  !! @param[in] ic the column index of the element
 
878
  !! @param[in] dry_run @opt=.false., if `.true.` will do nothing but issue error messages as though it had runned.
 
879
  recursive subroutine add_element_(this, ir, ic, dry_run)
 
880
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
881
    integer(BUD_TYPE_VAR_PREC), intent(in) :: ir, ic
 
882
    logical, intent(in), optional :: dry_run
 
883
 
 
884
    logical :: ldry
 
885
    type(BUD_TYPE_NAME) :: nthis
 
886
    integer(BUD_TYPE_VAR_PREC) :: i, r, ix, nr, nc, npr
 
887
 
 
888
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: ptr(:), nrow(:), col(:)
 
889
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: ptr_(:), nrow_(:), col_(:)
 
890
 
 
891
    ldry = .false.
 
892
    if ( present(dry_run) ) ldry = dry_run
 
893
 
 
894
    call attach(this, nr=nr, nc=nc, &
 
895
      rptr=ptr, nrow=nrow, col=col)
 
896
 
 
897
    ! check if there is place in the sparse matrix
 
898
    ! for an entry without re-allocation
 
899
    if ( ptr(ir+ONE) - ptr(ir) > nrow(ir) ) then
 
900
 
 
901
      ix = ptr(ir) BUD_SM_PTR_A +nrow(ir)
 
902
      if ( nrow(ir) == 0 ) then
 
903
        i = 0
 
904
      else
 
905
        i = col(ix - ONE)
 
906
      end if
 
907
      if ( .not. ldry ) then
 
908
        col(ix) = ic
 
909
        nrow(ir) = nrow(ir) + ONE
 
910
        this%D%nz = this%D%nz + ONE
 
911
 
 
912
        if ( this%D%sorted .and. ic < i ) then
 
913
 
 
914
          ! denote it non-sorted
 
915
          this%D%sorted = .false.
 
916
 
 
917
        end if
 
918
      end if
 
919
 
 
920
      call set_error(this, 0)
 
921
 
 
922
      return
 
923
 
 
924
    end if
 
925
 
 
926
    ! Re-allocate the sparse matrix and copy it
 
927
    ! We add 8 elements per row.
 
928
    ! Perhaps this should be defined by the user.
 
929
    npr = maxval(nrow) + BUD_CC2(8_,BUD_TYPE_VAR_PREC)
 
930
    ! Quick return if user request dry-run
 
931
    if ( ldry ) then
 
932
      call set_error(this, npr)
 
933
      return
 
934
    end if
 
935
 
 
936
    call new(nthis, nr, nc, npr=npr)
 
937
    call attach(nthis, rptr=ptr_, nrow=nrow_, col=col_)
 
938
 
 
939
    ! Copy all elements correctly
 
940
    ix = ONE
 
941
    do r = 1 , nr
 
942
      nrow_(r) = nrow(r)
 
943
 
 
944
      ix = ptr_(r) BUD_SM_PTR_A
 
945
      ! copy this row
 
946
      do i = ptr(r) BUD_SM_PTR_A , ptr(r) + nrow(r) BUD_SM_PTR_B
 
947
        col_(ix) = col(i)
 
948
        ix = ix + ONE
 
949
      end do
 
950
 
 
951
    end do
 
952
 
 
953
    ! add the element to the new sparse pattern
 
954
    call add_element(nthis, ir, ic)
 
955
    ! copy the sparse pattern to this one
 
956
    this = nthis
 
957
    ! clean-up
 
958
    call delete(nthis)
 
959
    ! specify the error message which then
 
960
    ! is the new size per row
 
961
    call set_error(this, npr)
 
962
 
 
963
  end subroutine add_element_
 
964
 
 
965
 
 
966
  !> @param[in] sp1 the first sparse matrix
 
967
  !! @param[in] sp2 the second sparse matrix
 
968
  !! @param[inout] sp the union of `sp1` and `sp2`
 
969
  subroutine union_(sp1, sp2, sp)
 
970
 
 
971
    use BUD_CC3(BUD_MOD,_,BUD_LIST_NAME)
 
972
 
 
973
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: sp1, sp2
 
974
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: sp
 
975
 
 
976
    type(BUD_LIST_NAME) :: L1, L2, L
 
977
    integer(BUD_TYPE_VAR_PREC) :: ir, n, nr, nc, nz
 
978
    integer(BUD_TYPE_VAR_PREC), allocatable :: rptr(:)
 
979
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: col(:)
 
980
 
 
981
    ! A union removes duplicate entries...
 
982
    ! This may be undesired.. :(
 
983
    call attach(sp1, nr=nr, nc=nc)
 
984
 
 
985
    ! Create a list with the pointers
 
986
    allocate(rptr(nr+1))
 
987
    rptr(1) = BUD_SM_PTR
 
988
    do ir = 1 , nr
 
989
 
 
990
      ! Create union...
 
991
      col => column_p(sp1, ir)
 
992
      n = size(col)
 
993
      call new(L1, n, col)
 
994
      col => column_p(sp2, ir)
 
995
      n = size(col)
 
996
      call new(L2, n, col)
 
997
 
 
998
      ! Sort both lists (makes unions faster)
 
999
      call sort(L1)
 
1000
      call sort(L2)
 
1001
 
 
1002
      ! Create union...
 
1003
      call union(L1, L2, L2)
 
1004
      ! We also ensure it is sorted.
 
1005
      call sort(L2)
 
1006
 
 
1007
      ! push the rows to the new list
 
1008
      call push(L, L2)
 
1009
 
 
1010
      rptr(ir+1) = rptr(ir) + size(L2)
 
1011
 
 
1012
    end do
 
1013
 
 
1014
    col => list_p(L)
 
1015
    call new(sp, nr, nc, nz, rptr, col)
 
1016
 
 
1017
    call delete(L1)
 
1018
    call delete(L2)
 
1019
    call delete(L)
 
1020
 
 
1021
  end subroutine union_
 
1022
 
 
1023
 
 
1024
  !> @param[in] from the originating sparse matrix
 
1025
  !! @param[in] n number of elements in `remove`
 
1026
  !! @param[in] remove columns that are removed
 
1027
  !! @param[inout] to sparse matrix after deleting the columns
 
1028
  subroutine remove_col_el_(from, n, remove, to)
 
1029
 
 
1030
    use BUD_CC3(BUD_MOD,_,BUD_LIST_NAME)
 
1031
 
 
1032
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: from
 
1033
    integer(BUD_TYPE_VAR_PREC), intent(in) :: n, remove(n)
 
1034
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: to
 
1035
 
 
1036
    type(BUD_LIST_NAME) :: lrem
 
1037
 
 
1038
    ! Create a new list
 
1039
    call new(lrem, n, remove)
 
1040
    call sort(lrem)
 
1041
 
 
1042
    call remove_col_list_(from, lrem, to)
 
1043
 
 
1044
    call delete(lrem)
 
1045
 
 
1046
  end subroutine remove_col_el_
 
1047
 
 
1048
  !> @param[in] from the originating sparse matrix
 
1049
  !! @param[in] remove list with columns that are removed
 
1050
  !! @param[inout] to sparse matrix after deleting the columns
 
1051
  subroutine remove_col_list_(from, remove, to)
 
1052
 
 
1053
    use BUD_CC3(BUD_MOD,_,BUD_LIST_NAME)
 
1054
 
 
1055
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: from
 
1056
    BUD_CLASS(BUD_LIST_NAME), intent(in) :: remove
 
1057
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: to
 
1058
 
 
1059
    type(BUD_LIST_NAME) :: ll
 
1060
    integer(BUD_TYPE_VAR_PREC) :: i, n
 
1061
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: lst(:)
 
1062
 
 
1063
    ! Create a new list
 
1064
    n = size(remove)
 
1065
    call new(ll, n)
 
1066
    lst => list_p(ll)
 
1067
    do i = 1 , n
 
1068
      lst(i) = -1
 
1069
    end do
 
1070
 
 
1071
    call translate_col_list_(from, remove, ll, to)
 
1072
 
 
1073
    call delete(ll)
 
1074
 
 
1075
  end subroutine remove_col_list_
 
1076
 
 
1077
 
 
1078
  !> @param[in] from the originating sparse matrix
 
1079
  !! @param[in] nin number of elements in `in_col`
 
1080
  !! @param[in] in_col the set of columns that will be translated into `out_col` (preferentially this should be sorted)
 
1081
  !! @param[in] nout number of elements in `out_col`
 
1082
  !! @param[in] out_col the set of translation columns
 
1083
  !! @param[inout] to the resulting sparse matrix after translating the columns
 
1084
  subroutine translate_col_el_(from, nin, in_col, nout, out_col, to)
 
1085
 
 
1086
    use BUD_CC3(BUD_MOD,_,BUD_LIST_NAME)
 
1087
 
 
1088
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: from
 
1089
    integer(BUD_TYPE_VAR_PREC), intent(in) :: nin, in_col(nin), nout, out_col(nout)
 
1090
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: to
 
1091
 
 
1092
    type(BUD_LIST_NAME) :: lin, lout
 
1093
 
 
1094
    call new(lin, nin, in_col)
 
1095
    call new(lout, nout, out_col)
 
1096
 
 
1097
    call translate_col_list_(from, lin, lout, to)
 
1098
 
 
1099
    call delete(lin)
 
1100
    call delete(lout)
 
1101
 
 
1102
  end subroutine translate_col_el_
 
1103
 
 
1104
 
 
1105
  !> @param[in] from the originating sparse matrix
 
1106
  !! @param[in] in_col a list set of columns that will be translated into `out_col` (preferentially this should be sorted)
 
1107
  !! @param[in] out_col a list set of translation columns
 
1108
  !! @param[inout] to the resulting sparse matrix after translating the columns
 
1109
  subroutine translate_col_list_(from, in_col, out_col, to)
 
1110
 
 
1111
    use BUD_CC3(BUD_MOD,_,BUD_LIST_NAME)
 
1112
 
 
1113
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: from
 
1114
    BUD_CLASS(BUD_LIST_NAME) :: in_col, out_col
 
1115
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: to
 
1116
 
 
1117
    type(BUD_LIST_NAME) :: lcol
 
1118
    integer(BUD_TYPE_VAR_PREC) :: nr, nc, nz, ir, i, idx
 
1119
    integer(BUD_TYPE_VAR_PREC), allocatable :: trptr(:)
 
1120
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: rptr(:), nrow(:), col(:)
 
1121
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: oc(:)
 
1122
 
 
1123
    call attach(from, nr=nr, nc=nc, nz=nz, rptr=rptr, col=col, nrow=nrow)
 
1124
 
 
1125
    ! Retrieve list
 
1126
    oc => list_p(out_col)
 
1127
 
 
1128
    ! Create a list with the columns
 
1129
    call new(lcol, nz)
 
1130
    allocate(trptr(nr+1))
 
1131
 
 
1132
    ! Now start create the sparse matrix
 
1133
    trptr(1) = rptr(1)
 
1134
    do ir = 1, nr
 
1135
 
 
1136
      ! figure out if they should be translated
 
1137
      do i = rptr(ir) BUD_SM_PTR_A, rptr(ir) + nrow(ir) BUD_SM_PTR_B
 
1138
        idx = index(in_col, col(i))
 
1139
        if ( idx <= 0 ) then
 
1140
          call push(lcol, col(i))
 
1141
        else if ( oc(idx) > 0 ) then
 
1142
          ! we have a translation
 
1143
          ! check if the resulting translated column is
 
1144
          ! negative, if so, it means deletion
 
1145
 
 
1146
          ! we retain the item
 
1147
          call push(lcol, oc(idx))
 
1148
        end if
 
1149
      end do
 
1150
 
 
1151
      ! update the following pointer
 
1152
      trptr(ir+1) = size(lcol) + BUD_SM_PTR
 
1153
 
 
1154
    end do
 
1155
 
 
1156
    col => list_p(lcol)
 
1157
    call new(to, nr, nc, size(lcol), trptr, col)
 
1158
 
 
1159
    call delete(lcol)
 
1160
 
 
1161
  end subroutine translate_col_list_
 
1162
 
 
1163
 
 
1164
  !> @param[in] from the originating sparse matrix
 
1165
  !! @param[in] n number of elements in `remove`
 
1166
  !! @param[in] remove rows that are removed
 
1167
  !! @param[inout] to sparse matrix after deleting the rows
 
1168
  subroutine remove_row_el_(from, n, remove, to)
 
1169
 
 
1170
    use BUD_CC3(BUD_MOD,_,BUD_LIST_NAME)
 
1171
 
 
1172
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: from
 
1173
    integer(BUD_TYPE_VAR_PREC), intent(in) :: n, remove(n)
 
1174
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: to
 
1175
 
 
1176
    type(BUD_LIST_NAME) :: lrem
 
1177
 
 
1178
    ! Create a new list
 
1179
    call new(lrem, n, remove)
 
1180
    call sort(lrem)
 
1181
 
 
1182
    call remove_row_list_(from, lrem, to)
 
1183
 
 
1184
    call delete(lrem)
 
1185
 
 
1186
  end subroutine remove_row_el_
 
1187
 
 
1188
  !> @param[in] from the originating sparse matrix
 
1189
  !! @param[in] remove list with rows that are removed
 
1190
  !! @param[inout] to sparse matrix after deleting the rows
 
1191
  subroutine remove_row_list_(from, remove, to)
 
1192
 
 
1193
    use BUD_CC3(BUD_MOD,_,BUD_LIST_NAME)
 
1194
 
 
1195
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: from
 
1196
    BUD_CLASS(BUD_LIST_NAME), intent(in) :: remove
 
1197
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: to
 
1198
 
 
1199
    type(BUD_LIST_NAME) :: ll
 
1200
    integer(BUD_TYPE_VAR_PREC) :: i, n
 
1201
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: lst(:)
 
1202
 
 
1203
    ! Create a new list
 
1204
    n = size(remove)
 
1205
    call new(ll, n)
 
1206
    lst => list_p(ll)
 
1207
    do i = 1 , n
 
1208
      lst(i) = -1
 
1209
    end do
 
1210
 
 
1211
    call translate_row_list_(from, remove, ll, to)
 
1212
 
 
1213
    call delete(ll)
 
1214
 
 
1215
  end subroutine remove_row_list_
 
1216
 
 
1217
 
 
1218
 
 
1219
  !> @param[in] from the originating sparse matrix
 
1220
  !! @param[in] nin number of elements in `in_row`
 
1221
  !! @param[in] in_row the set of rows that will be translated into `out_row` (preferentially this should be sorted)
 
1222
  !! @param[in] nout number of elements in `out_row`
 
1223
  !! @param[in] out_row the set of translation rows
 
1224
  !! @param[inout] to the resulting sparse matrix after translating the rows
 
1225
  subroutine translate_row_el_(from, nin, in_row, nout, out_row, to)
 
1226
 
 
1227
    use BUD_CC3(BUD_MOD,_,BUD_LIST_NAME)
 
1228
 
 
1229
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: from
 
1230
    integer(BUD_TYPE_VAR_PREC), intent(in) :: nin, in_row(nin), nout, out_row(nout)
 
1231
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: to
 
1232
 
 
1233
    type(BUD_LIST_NAME) :: lin, lout
 
1234
 
 
1235
    call new(lin, nin, in_row)
 
1236
    call new(lout, nout, out_row)
 
1237
 
 
1238
    call translate_row_list_(from, lin, lout, to)
 
1239
 
 
1240
    call delete(lin)
 
1241
    call delete(lout)
 
1242
 
 
1243
  end subroutine translate_row_el_
 
1244
 
 
1245
  !> @param[in] from the originating sparse matrix
 
1246
  !! @param[in] in_row a list set of rows that will be translated into `out_row`
 
1247
  !! @param[in] out_row a list set of translation rows (preferentially this should be sorted)
 
1248
  !! @param[inout] to the resulting sparse matrix after translating the rows
 
1249
  subroutine translate_row_list_(from, in_row, out_row, to)
 
1250
 
 
1251
    use BUD_CC3(BUD_MOD,_,BUD_LIST_NAME)
 
1252
 
 
1253
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: from
 
1254
    BUD_CLASS(BUD_LIST_NAME) :: in_row, out_row
 
1255
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: to
 
1256
 
 
1257
    type(BUD_LIST_NAME), allocatable :: lrow(:)
 
1258
    type(BUD_LIST_NAME) :: tmp
 
1259
    integer(BUD_TYPE_VAR_PREC) :: nr, nc, nnr, r, ir, i, idx
 
1260
    integer(BUD_TYPE_VAR_PREC), allocatable :: rptr(:)
 
1261
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: row(:), col(:)
 
1262
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: or(:)
 
1263
 
 
1264
    call attach(from, nr=nr, nc=nc)
 
1265
 
 
1266
    ! This algorithm moves in_row to out_row, and possibly deletes
 
1267
    ! rows.
 
1268
    allocate(lrow(nc))
 
1269
 
 
1270
    ! Initialize the sparse lists
 
1271
    do ir = 1 , nr
 
1272
      call new(lrow(ir), ONE)
 
1273
    end do
 
1274
 
 
1275
    ! List of out rows
 
1276
    or => list_p(out_row)
 
1277
 
 
1278
    ! Now actually populate the sparse rows
 
1279
    do ir = 1 , nr
 
1280
 
 
1281
      ! Get rows in current column
 
1282
      col => column_p(from, ir)
 
1283
      i = int(size(col), BUD_TYPE_VAR_PREC)
 
1284
 
 
1285
      ! Figure out if this is in in_row (i.e. should it be translated)
 
1286
      idx = index(in_row, ir)
 
1287
      if ( idx < 1 ) then
 
1288
 
 
1289
        ! The column is not translated
 
1290
        call push(lrow(ir), i, col)
 
1291
 
 
1292
      else if ( or(idx) >= BUD_SM_IDX(1) ) then
 
1293
 
 
1294
        ! Find where the new column has moved
 
1295
        r = BUD_SM_IDXF(or(idx))
 
1296
        call push(lrow(r), i, col)
 
1297
 
 
1298
      end if
 
1299
 
 
1300
    end do
 
1301
 
 
1302
    ! Now re-create the new sparsity pattern
 
1303
    ! First figure out the new number of rows...
 
1304
    row => list_p(in_row)
 
1305
    nnr = nr
 
1306
    do i = 1 , size(in_row)
 
1307
      idx = index(out_row, row(i))
 
1308
      if ( idx <= 0 ) then
 
1309
        ! We also delete the row, so we may recognize it
 
1310
        call delete(lrow(row(i)))
 
1311
        nnr = nnr - 1
 
1312
      end if
 
1313
    end do
 
1314
 
 
1315
    ! Now re-create the pointers
 
1316
    allocate(rptr(nnr+1))
 
1317
    rptr(1) = BUD_SM_PTR
 
1318
    ! Loop on old rows
 
1319
    ir = 0
 
1320
    do r = 1 , nr
 
1321
 
 
1322
      ! if the list has been deleted, simply
 
1323
      ! skip
 
1324
      if ( .not. is_initd(lrow(r)) ) cycle
 
1325
      ir = ir + 1
 
1326
 
 
1327
      ! Create full list of columns
 
1328
      call push(tmp, lrow(r))
 
1329
 
 
1330
      ! Create the pointer
 
1331
      rptr(ir+1) = rptr(ir) + size(lrow(r))
 
1332
 
 
1333
      call delete(lrow(r))
 
1334
 
 
1335
    end do
 
1336
 
 
1337
    ! Now we have, rptr, and column
 
1338
    col => list_p(tmp)
 
1339
    ! finally we also know that all elements of lrow
 
1340
    ! has been deleted
 
1341
 
 
1342
    call new(to, nnr, nc, size(tmp), rptr, col)
 
1343
 
 
1344
    call delete(tmp)
 
1345
    deallocate(lrow)
 
1346
 
 
1347
  end subroutine translate_row_list_
 
1348
 
 
1349
 
 
1350
  !> @param[inout] f `File` bud
 
1351
  !! @param[in] this the sparse matrix bud
 
1352
  subroutine write_(f, this)
 
1353
    use BUD_CC2(BUD_MOD,_File)
 
1354
 
 
1355
    BUD_CLASS( BUD_CC2(BUD_TYPE,File) ), intent(inout) :: f
 
1356
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
1357
 
 
1358
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: col(:), nrow(:)
 
1359
 
 
1360
    logical :: formatted
 
1361
    integer :: iu
 
1362
 
 
1363
    integer(BUD_TYPE_VAR_PREC) :: nz
 
1364
    integer(BUD_TYPE_VAR_PREC) :: ir
 
1365
    integer(BUD_TYPE_VAR_PREC) :: nr, nc
 
1366
 
 
1367
    ! If file is not opened, return immediately
 
1368
    if ( .not. is_open(f) ) return
 
1369
    if ( .not. is_initd(this) ) return
 
1370
 
 
1371
    ! First figure out if the file is an unformatted file
 
1372
    formatted = is_formatted(f)
 
1373
    iu = unit(f)
 
1374
 
 
1375
    call attach(this, nr=nr, nc=nc, nz=nz, nrow=nrow)
 
1376
 
 
1377
    ! First we write the size of the sparse matrix
 
1378
    if ( formatted ) then
 
1379
      write(iu, '(i16)') nr, nc, nz
 
1380
      write(iu, '(l16)') this%D%sorted
 
1381
      write(iu, '(i16)') nrow(:)
 
1382
    else
 
1383
      write(iu) nr, nc, nz
 
1384
      write(iu) this%D%sorted
 
1385
      write(iu) nrow(:)
 
1386
    end if
 
1387
 
 
1388
    ! Write the sparse columns
 
1389
    do ir = 1 , nr
 
1390
      col => column_p(this, ir)
 
1391
      if ( formatted ) then
 
1392
        write(iu, '(i16)') col(:)
 
1393
      else
 
1394
        write(iu) col(:)
 
1395
      end if
 
1396
    end do
 
1397
 
 
1398
  end subroutine write_
 
1399
 
 
1400
  !> @param[inout] f `File` bud
 
1401
  !! @param[inout] this the sparse matrix bud
 
1402
  subroutine read_(f, this)
 
1403
    use BUD_CC2(BUD_MOD,_File)
 
1404
 
 
1405
    BUD_CLASS( BUD_CC2(BUD_TYPE,File) ), intent(inout) :: f
 
1406
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
1407
 
 
1408
    integer(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: ptr(:), col(:), nrow(:)
 
1409
 
 
1410
    logical :: formatted
 
1411
    integer :: iu
 
1412
 
 
1413
    logical :: sorted
 
1414
    integer(BUD_TYPE_VAR_PREC) :: nz, i
 
1415
    integer(BUD_TYPE_VAR_PREC) :: ir
 
1416
    integer(BUD_TYPE_VAR_PREC) :: nr, nc
 
1417
 
 
1418
    ! If file is not opened, return immediately
 
1419
    if ( .not. is_open(f) ) return
 
1420
 
 
1421
    ! First figure out if the file is an unformatted file
 
1422
    formatted = is_formatted(f)
 
1423
    iu = unit(f)
 
1424
 
 
1425
    ! First we need to read the array dimensions...
 
1426
    if ( formatted ) then
 
1427
      read(iu, '(i16)') nr, nc, nz
 
1428
      read(iu, '(l16)') sorted
 
1429
    else
 
1430
      read(iu) nr, nc, nz
 
1431
      read(iu) sorted
 
1432
    end if
 
1433
 
 
1434
    call new(this, nr, nc, nz)
 
1435
    call attach(this, rptr=ptr, nrow=nrow)
 
1436
 
 
1437
    ! Read nrow
 
1438
    if ( formatted ) then
 
1439
      read(iu, '(i16)') nrow
 
1440
    else
 
1441
      read(iu) nrow
 
1442
    end if
 
1443
 
 
1444
    ! Create the pointer array
 
1445
    ptr(1) = BUD_SM_PTR
 
1446
    do i = 2 , nr + 1
 
1447
      ptr(i) = ptr(i-1) + nrow(i-1)
 
1448
    end do
 
1449
 
 
1450
    ! Read the sparse columns
 
1451
    do ir = 1 , nr
 
1452
      col => column_p(this, ir)
 
1453
      if ( formatted ) then
 
1454
        read(iu, '(i16)') col(:)
 
1455
      else
 
1456
        read(iu) col(:)
 
1457
      end if
 
1458
    end do
 
1459
 
 
1460
    this%D%sorted = sorted
 
1461
    this%D%finalized = .true.
 
1462
 
 
1463
  end subroutine read_
 
1464
 
 
1465
 
 
1466
! Local pre-processor variables that
 
1467
! undefine the variables that are not needed anymore.
 
1468
#undef BUD_MOD_NAME
 
1469
#undef BUD_LIST_NAME
 
1470
#undef BUD_TYPE_NAME
 
1471
#undef BUD_TYPE_NAME_
 
1472
#undef BUD_TYPE_NAME_STR
 
1473
#undef BUD_TYPE_VAR
 
1474
#undef BUD_TYPE_VAR_PREC
 
1475
 
 
1476
  ! Control variables
 
1477
#undef BUD_SM_CSR
 
1478
#undef BUD_SM_INTEROP_C
 
1479
#undef BUD_SM_MOD
 
1480
#undef BUD_SM_IDX
 
1481
#undef BUD_SM_IDXF
 
1482
 
 
1483
#include "bud_cleanup.inc"
 
1484
 
 
1485
 
 
1486
! project-buds -- local file settings
 
1487
!     Anything below this line may be overwritten by scripts
 
1488
!     Below are non-editable settings
 
1489
 
 
1490
! Local Variables:
 
1491
!  mode: f90
 
1492
!  f90-if-indent: 2
 
1493
!  f90-type-indent: 2
 
1494
!  f90-associate-indent: 2
 
1495
!  f90-continuation-indent: 2
 
1496
!  f90-structure-indent: 2
 
1497
!  f90-critical-indent: 2
 
1498
!  f90-program-indent: 2
 
1499
!  f90-do-indent: 2
 
1500
! End:
 
1501