@@ -109,6 +109,9 @@ module numerical_differentiation_module
109
109
real (wp),dimension (:),allocatable :: xlow ! ! lower bounds on `x`
110
110
real (wp),dimension (:),allocatable :: xhigh ! ! upper bounds on `x`
111
111
112
+ logical :: print_messages = .true. ! ! if true, warning messages are printed
113
+ ! ! to the `error_unit` for any errors.
114
+
112
115
integer :: chunk_size = 100 ! ! chuck size for allocating the arrays (>0)
113
116
114
117
integer :: perturb_mode = 1 ! ! perturbation mode:
@@ -416,9 +419,8 @@ subroutine get_formula(me,formula)
416
419
character (len= :),allocatable ,intent (out ) :: formula
417
420
418
421
integer :: i ! ! counter
419
- integer :: istat ! ! write `iostat` flag
420
- character (len= 10 ) :: x ! ! temp variable for integer to string conversion
421
- character (len= 10 ) :: f ! ! temp variable for integer to string conversion
422
+ character (len= :),allocatable :: x ! ! temp variable for integer to string conversion
423
+ character (len= :),allocatable :: f ! ! temp variable for integer to string conversion
422
424
423
425
if (allocated (me% dx_factors) .and. allocated (me% df_factors)) then
424
426
@@ -436,9 +438,9 @@ subroutine get_formula(me,formula)
436
438
formula = formula// ' -f('
437
439
else
438
440
if (i== 1 ) then
439
- write (f, ' (I10) ' ,iostat = istat) int (me% df_factors(i)) ! integer to string
441
+ f = integer_to_string( int (me% df_factors(i)))
440
442
else
441
- write (f, ' (SP,I10) ' ,iostat = istat) int (me% df_factors(i)) ! integer to string (with sign )
443
+ f = integer_to_string( int (me% df_factors(i)), with_sign = .true. )
442
444
end if
443
445
formula = formula// trim (adjustl (f))// ' f('
444
446
end if
@@ -450,15 +452,15 @@ subroutine get_formula(me,formula)
450
452
elseif (int (me% dx_factors(i))==- 1 ) then
451
453
formula = formula// ' x-h'
452
454
else
453
- write (x, ' (SP,I10) ' ,iostat = istat) int (me% dx_factors(i)) ! integer to string (with sign )
455
+ x = integer_to_string( int (me% dx_factors(i)), with_sign = .true. )
454
456
formula = formula// ' x' // trim (adjustl (x))// ' h'
455
457
end if
456
458
457
459
formula = formula// ' )'
458
460
459
461
end do
460
462
461
- write (f, ' (I10) ' ,iostat = istat) int (me% df_den_factor) ! integer to string
463
+ f = integer_to_string( int (me% df_den_factor))
462
464
if (int (me% df_den_factor)==1 ) then
463
465
formula = formula// ' ) / h'
464
466
else
@@ -854,20 +856,25 @@ subroutine select_finite_diff_method(me,x,xlow,xhigh,dx,list_of_methods,fd,statu
854
856
855
857
integer :: i ! ! counter
856
858
integer :: j ! ! counter
859
+ real (wp) :: xs ! ! if `x` is outside the bounds, this is the value
860
+ ! ! on the nearest bound. otherwise equal to `x`.
857
861
real (wp) :: xp ! ! perturbed `x` value
858
862
859
863
! initialize:
860
864
status_ok = .false.
861
865
862
866
if (me% exception_raised) return ! check for exceptions
863
867
868
+ ! make sure it is within the bounds
869
+ xs = min (xhigh,max (xlow,x))
870
+
864
871
! try all the methods in the class:
865
872
do i = 1 , size (list_of_methods% meth)
866
873
status_ok = .true. ! will be set to false if any
867
874
! perturbation violates the bounds
868
875
! check each of the perturbations:
869
876
do j = 1 , size (list_of_methods% meth(i)% dx_factors)
870
- xp = x + list_of_methods% meth(i)% dx_factors(j)* dx
877
+ xp = xs + list_of_methods% meth(i)% dx_factors(j)* dx
871
878
if (xp < xlow .or. xp > xhigh) then
872
879
status_ok = .false.
873
880
exit
@@ -915,19 +922,24 @@ subroutine select_finite_diff_method_for_partition_group(me,x,xlow,xhigh,dx,&
915
922
integer :: i ! ! counter
916
923
integer :: j ! ! counter
917
924
real (wp),dimension (size (x)) :: xp ! ! perturbed `x` values
925
+ real (wp),dimension (size (x)) :: xs ! ! if `x` is outside the bounds, this is the value
926
+ ! ! on the nearest bound. otherwise equal to `x`.
918
927
919
928
! initialize:
920
929
status_ok = .false.
921
930
922
931
if (me% exception_raised) return ! check for exceptions
923
932
933
+ ! make sure they are within the bounds
934
+ xs = min (xhigh,max (xlow,x))
935
+
924
936
! try all the methods in the class:
925
937
do i = 1 , size (list_of_methods% meth)
926
938
status_ok = .true. ! will be set to false if any
927
939
! perturbation violates the bounds
928
940
! check each of the perturbations:
929
941
do j = 1 , size (list_of_methods% meth(i)% dx_factors)
930
- xp = x + list_of_methods% meth(i)% dx_factors(j)* dx
942
+ xp = xs + list_of_methods% meth(i)% dx_factors(j)* dx
931
943
if (any (xp < xlow) .or. any (xp > xhigh)) then
932
944
status_ok = .false.
933
945
exit
@@ -959,7 +971,7 @@ subroutine initialize_numdiff_for_diff(me,n,m,xlow,xhigh,&
959
971
xlow_for_sparsity ,xhigh_for_sparsity ,&
960
972
dpert_for_sparsity ,sparsity_perturb_mode ,&
961
973
linear_sparsity_tol ,function_precision_tol ,&
962
- num_sparsity_points )
974
+ num_sparsity_points , print_messages )
963
975
964
976
implicit none
965
977
@@ -1015,6 +1027,8 @@ subroutine initialize_numdiff_for_diff(me,n,m,xlow,xhigh,&
1015
1027
! ! considered the same value. This is used
1016
1028
! ! when estimating the sparsity pattern when
1017
1029
! ! `sparsity_mode=2` in [[compute_sparsity_random]]
1030
+ logical ,intent (in ),optional :: print_messages ! ! if true, print error messages to `error_unit`.
1031
+ ! ! default is True.
1018
1032
1019
1033
logical :: cache ! ! if the cache is to be used
1020
1034
@@ -1070,10 +1084,11 @@ subroutine initialize_numdiff_for_diff(me,n,m,xlow,xhigh,&
1070
1084
if (present (num_sparsity_points)) me% num_sparsity_points = num_sparsity_points
1071
1085
1072
1086
! optional:
1073
- if (present (chunk_size)) me% chunk_size = abs (chunk_size)
1074
- if (present (eps)) me% eps = eps
1075
- if (present (acc)) me% acc = acc
1076
- if (present (info)) me% info_function = > info
1087
+ if (present (chunk_size)) me% chunk_size = abs (chunk_size)
1088
+ if (present (eps)) me% eps = eps
1089
+ if (present (acc)) me% acc = acc
1090
+ if (present (info)) me% info_function = > info
1091
+ if (present (print_messages)) me% print_messages = print_messages
1077
1092
1078
1093
end subroutine initialize_numdiff_for_diff
1079
1094
! *******************************************************************************
@@ -1098,7 +1113,7 @@ subroutine set_numdiff_bounds(me,xlow,xhigh)
1098
1113
1099
1114
integer :: i ! ! counter for error print
1100
1115
character (len= :),allocatable :: error_info ! ! error message info
1101
- character (len= 10 ) :: istr ! ! for integer to string
1116
+ character (len= :), allocatable :: istr ! ! for integer to string
1102
1117
character (len= 30 ) :: xlow_str, xhigh_str ! ! for real to string
1103
1118
1104
1119
if (me% exception_raised) return ! check for exceptions
@@ -1114,7 +1129,7 @@ subroutine set_numdiff_bounds(me,xlow,xhigh)
1114
1129
error_info = ' all xlow must be < xhigh'
1115
1130
do i = 1 , size (xlow)
1116
1131
if (xlow(i)>= xhigh(i)) then
1117
- write ( istr, ' (I10) ' ) i
1132
+ istr = integer_to_string(i)
1118
1133
write (xlow_str,' (F30.16)' ) xlow(i)
1119
1134
write (xhigh_str,' (F30.16)' ) xhigh(i)
1120
1135
error_info = error_info// new_line(' ' )// ' Error for optimization variable ' // trim (adjustl (istr))// &
@@ -1520,15 +1535,17 @@ subroutine dsm_wrapper(me,n,m,info)
1520
1535
integer ,intent (out ) :: info ! ! status output from [[dsm]]
1521
1536
1522
1537
integer :: mingrp ! ! for call to [[dsm]]
1523
- integer ,dimension (m+1 ) :: ipntr ! ! for call to [[dsm]]
1524
- integer ,dimension (n+1 ) :: jpntr ! ! for call to [[dsm]]
1525
- integer ,dimension (:),allocatable :: irow ! ! for call to [[dsm]]
1526
- ! ! (temp copy since [[dsm]]
1527
- ! ! will modify it)
1528
- integer ,dimension (:),allocatable :: icol ! ! for call to [[dsm]]
1529
- ! ! (temp copy since [[dsm]]
1530
- ! ! will modify it)
1531
-
1538
+ integer ,dimension (:),allocatable :: ipntr ! ! for call to [[dsm]]
1539
+ integer ,dimension (:),allocatable :: jpntr ! ! for call to [[dsm]]
1540
+ integer ,dimension (:),allocatable :: irow ! ! for call to [[dsm]]
1541
+ ! ! (temp copy since [[dsm]]
1542
+ ! ! will modify it)
1543
+ integer ,dimension (:),allocatable :: icol ! ! for call to [[dsm]]
1544
+ ! ! (temp copy since [[dsm]]
1545
+ ! ! will modify it)
1546
+
1547
+ allocate (ipntr(m+1 ))
1548
+ allocate (jpntr(n+1 ))
1532
1549
allocate (me% ngrp(n))
1533
1550
irow = me% irow
1534
1551
icol = me% icol
@@ -1644,7 +1661,7 @@ end subroutine compute_indices
1644
1661
! @note If specifying the linear pattern, all three optional arguments
1645
1662
! must be present.
1646
1663
1647
- subroutine set_sparsity_pattern (me ,irow ,icol ,linear_irow ,linear_icol ,linear_vals )
1664
+ subroutine set_sparsity_pattern (me ,irow ,icol ,linear_irow ,linear_icol ,linear_vals , maxgrp , ngrp )
1648
1665
1649
1666
implicit none
1650
1667
@@ -1654,6 +1671,10 @@ subroutine set_sparsity_pattern(me,irow,icol,linear_irow,linear_icol,linear_vals
1654
1671
integer ,dimension (:),intent (in ),optional :: linear_irow ! ! linear sparsity pattern nonzero elements row indices
1655
1672
integer ,dimension (:),intent (in ),optional :: linear_icol ! ! linear sparsity pattern nonzero elements column indices
1656
1673
real (wp),dimension (:),intent (in ),optional :: linear_vals ! ! linear sparsity values (constant elements of the Jacobian)
1674
+ integer ,intent (in ),optional :: maxgrp ! ! DSM sparsity partition
1675
+ ! ! [only used if `me%partition_sparsity_pattern=True`]
1676
+ integer ,dimension (:),intent (in ),optional :: ngrp ! ! DSM sparsity partition (size `n`)
1677
+ ! ! [only used if `me%partition_sparsity_pattern=True`]
1657
1678
1658
1679
integer :: info ! ! status output form [[dsm]]
1659
1680
@@ -1674,11 +1695,23 @@ subroutine set_sparsity_pattern(me,irow,icol,linear_irow,linear_icol,linear_vals
1674
1695
1675
1696
call me% sparsity% compute_indices()
1676
1697
if (me% partition_sparsity_pattern) then
1677
- call me% sparsity% dsm_wrapper(me% n,me% m,info)
1678
- if (info/= 1 ) then
1679
- call me% raise_exception(16 ,' set_sparsity_pattern' ,&
1680
- ' error partitioning sparsity pattern.' )
1681
- return
1698
+ if (present (maxgrp) .and. present (ngrp)) then
1699
+ ! use the user-input partition:
1700
+ if (maxgrp> 0 .and. all (ngrp>= 1 .and. ngrp<= maxgrp) .and. size (ngrp)==me% n) then
1701
+ me% sparsity% maxgrp = maxgrp
1702
+ me% sparsity% ngrp = ngrp
1703
+ else
1704
+ call me% raise_exception(28 ,' set_sparsity_pattern' ,&
1705
+ ' invalid sparsity partition inputs.' )
1706
+ return
1707
+ end if
1708
+ else
1709
+ call me% sparsity% dsm_wrapper(me% n,me% m,info)
1710
+ if (info/= 1 ) then
1711
+ call me% raise_exception(16 ,' set_sparsity_pattern' ,&
1712
+ ' error partitioning sparsity pattern.' )
1713
+ return
1714
+ end if
1682
1715
end if
1683
1716
end if
1684
1717
@@ -2148,7 +2181,9 @@ end subroutine compute_sparsity_pattern
2148
2181
! Returns the sparsity pattern from the class.
2149
2182
! If it hasn't been computed, the output arrays will not be allocated.
2150
2183
2151
- subroutine get_sparsity_pattern (me ,irow ,icol ,linear_irow ,linear_icol ,linear_vals )
2184
+ subroutine get_sparsity_pattern (me ,irow ,icol ,&
2185
+ linear_irow ,linear_icol ,linear_vals ,&
2186
+ maxgrp ,ngrp )
2152
2187
2153
2188
implicit none
2154
2189
@@ -2161,6 +2196,8 @@ subroutine get_sparsity_pattern(me,irow,icol,linear_irow,linear_icol,linear_vals
2161
2196
! ! elements column indices
2162
2197
real (wp),dimension (:),allocatable ,intent (out ),optional :: linear_vals ! ! linear sparsity values (constant
2163
2198
! ! elements of the Jacobian)
2199
+ integer ,intent (out ),optional :: maxgrp ! ! DSM sparsity partition
2200
+ integer ,dimension (:),allocatable ,intent (out ),optional :: ngrp ! ! DSM sparsity partition
2164
2201
2165
2202
if (me% exception_raised) return ! check for exceptions
2166
2203
@@ -2180,6 +2217,10 @@ subroutine get_sparsity_pattern(me,irow,icol,linear_irow,linear_icol,linear_vals
2180
2217
if (allocated (me% sparsity% linear_vals)) linear_vals = me% sparsity% linear_vals
2181
2218
end if
2182
2219
2220
+ ! optional DSM partition:
2221
+ if (present (ngrp) .and. allocated (me% sparsity% ngrp)) ngrp = me% sparsity% ngrp
2222
+ if (present (maxgrp)) maxgrp = me% sparsity% maxgrp
2223
+
2183
2224
end subroutine get_sparsity_pattern
2184
2225
! *******************************************************************************
2185
2226
@@ -2427,8 +2468,12 @@ subroutine compute_jacobian_for_sparsity(me,i,class_meths,x,jac)
2427
2468
2428
2469
call me% select_finite_diff_method(x(i),me% xlow_for_sparsity(i),me% xhigh_for_sparsity(i),&
2429
2470
dx(i),class_meths,fd,status_ok)
2430
- if (.not. status_ok) write (error_unit,' (A,1X,I5)' ) &
2431
- ' Error in compute_jacobian_for_sparsity: variable bounds violated for column: ' ,i
2471
+ if (.not. status_ok) then
2472
+ if (me% print_messages) then
2473
+ write (error_unit,' (A,1X,I5)' ) &
2474
+ ' Error in compute_jacobian_for_sparsity: variable bounds violated for column: ' ,i
2475
+ end if
2476
+ end if
2432
2477
2433
2478
! compute this column of the Jacobian:
2434
2479
df = zero
@@ -2512,8 +2557,12 @@ subroutine compute_jacobian_standard(me,x,dx,jac)
2512
2557
2513
2558
call me% select_finite_diff_method(x(i),me% xlow(i),me% xhigh(i),&
2514
2559
dx(i),me% class_meths(i),fd,status_ok)
2515
- if (.not. status_ok) write (error_unit,' (A,1X,I5)' ) &
2516
- ' Error in compute_jacobian_standard: variable bounds violated for column: ' ,i
2560
+ if (.not. status_ok) then
2561
+ if (me% print_messages) then
2562
+ write (error_unit,' (A,1X,I5)' ) &
2563
+ ' Error in compute_jacobian_standard: variable bounds violated for column: ' ,i
2564
+ end if
2565
+ end if
2517
2566
2518
2567
! compute this column of the Jacobian:
2519
2568
df = zero
@@ -2743,11 +2792,13 @@ subroutine compute_jacobian_partitioned(me,x,dx,jac)
2743
2792
dx(cols),me% class_meths(1 ),fd,status_ok)
2744
2793
2745
2794
if (.not. status_ok) then
2746
- ! will not consider this a fatal error for now:
2747
- write (error_unit,' (A,1X,I5,1X,A,1X,*(I5,1X))' ) &
2748
- ' Error in compute_jacobian_partitioned: ' // &
2749
- ' variable bounds violated for group: ' ,&
2750
- igroup,' . columns: ' ,cols
2795
+ if (me% print_messages) then
2796
+ ! will not consider this a fatal error for now:
2797
+ write (error_unit,' (A,1X,I5,1X,A,1X,*(I5,1X))' ) &
2798
+ ' Error in compute_jacobian_partitioned: ' // &
2799
+ ' variable bounds violated for group: ' ,&
2800
+ igroup,' . columns: ' ,cols
2801
+ end if
2751
2802
end if
2752
2803
2753
2804
! compute the columns of the Jacobian in this group:
@@ -3111,6 +3162,43 @@ subroutine get_error_status(me,istat,error_msg)
3111
3162
end subroutine get_error_status
3112
3163
! *******************************************************************************
3113
3164
3165
+ ! *******************************************************************************
3166
+ ! >
3167
+ ! Convert an integer to a string.
3168
+
3169
+ function integer_to_string (i , with_sign ) result(str)
3170
+
3171
+ implicit none
3172
+
3173
+ integer ,intent (in ) :: i ! ! the integer
3174
+ logical ,intent (in ),optional :: with_sign ! ! also include the sign (default is False)
3175
+ character (len= :),allocatable :: str ! ! integer converted to a string
3176
+
3177
+ integer :: istat ! ! `iostat` code for write statement
3178
+ character (len= 100 ) :: tmp ! !
3179
+ logical :: sgn ! ! local copy of `with_sign`
3180
+
3181
+ if (present (with_sign)) then
3182
+ sgn = with_sign
3183
+ else
3184
+ sgn = .false.
3185
+ end if
3186
+
3187
+ if (sgn) then
3188
+ write (tmp,' (SP,I100)' ,iostat= istat) i
3189
+ else
3190
+ write (tmp,' (I100)' ,iostat= istat) i
3191
+ end if
3192
+
3193
+ if (istat == 0 ) then
3194
+ str = trim (adjustl (tmp))
3195
+ else
3196
+ str = ' ****'
3197
+ end if
3198
+
3199
+ end function integer_to_string
3200
+ ! *******************************************************************************
3201
+
3114
3202
! *******************************************************************************
3115
3203
end module numerical_differentiation_module
3116
3204
! *******************************************************************************
0 commit comments