MODFLOW 6  version 6.7.0.dev0
USGS Modular Hydrologic Model
dag_module Module Reference

Data Types

type  vertex
 
type  dag
 

Functions/Subroutines

subroutine dag_destroy (me)
 
subroutine set_edge_vector (me, edges)
 
subroutine add_edge (me, edge)
 
pure integer function, dimension(:), allocatable dag_get_edges (me, ivertex)
 
pure integer function, dimension(:), allocatable dag_get_dependencies (me, ivertex)
 
subroutine dag_set_vertices (me, nvertices)
 
subroutine dag_set_vertex_info (me, ivertex, label, attributes)
 
subroutine dag_set_edges (me, ivertex, edges)
 
subroutine dag_toposort (me, order, istat)
 
character(len=:) function, allocatable dag_generate_digraph (me, rankdir, dpi, edge)
 
subroutine dag_generate_dependency_matrix (me, mat)
 
subroutine dag_save_digraph (me, filename, rankdir, dpi, edge)
 
pure character(len=:) function, allocatable integer_to_string (i)
 

Function/Subroutine Documentation

◆ add_edge()

subroutine dag_module::add_edge ( class(vertex), intent(inout)  me,
integer, intent(in)  edge 
)
private

Definition at line 88 of file dag_module.f90.

89 
90  class(vertex),intent(inout) :: me
91  integer,intent(in) :: edge
92 
93  if (allocated(me%edges)) then
94  if (.not. any(edge==me%edges)) then
95  me%edges = [me%edges, edge] ! auto lhs reallocation
96  end if
97  else
98  allocate(me%edges(1))
99  me%edges = [edge]
100  end if
101 
Here is the caller graph for this function:

◆ dag_destroy()

subroutine dag_module::dag_destroy ( class(dag), intent(inout)  me)

Definition at line 51 of file dag_module.f90.

52 
53  class(dag),intent(inout) :: me
54 
55  me%n = 0
56  if (allocated(me%vertices)) deallocate(me%vertices)
57 

◆ dag_generate_dependency_matrix()

subroutine dag_module::dag_generate_dependency_matrix ( class(dag), intent(in)  me,
logical, dimension(:,:), intent(out), allocatable  mat 
)
private

Definition at line 365 of file dag_module.f90.

366 
367  implicit none
368 
369  class(dag),intent(in) :: me
370  logical,dimension(:,:),intent(out),allocatable :: mat !! dependency matrix
371 
372  integer :: i !! vertex counter
373 
374  if (me%n > 0) then
375 
376  allocate(mat(me%n,me%n))
377  mat = .false.
378 
379  do i=1,me%n
380  if (allocated(me%vertices(i)%edges)) then
381  mat(i,me%vertices(i)%edges) = .true.
382  end if
383  end do
384 
385  end if
386 

◆ dag_generate_digraph()

character(len=:) function, allocatable dag_module::dag_generate_digraph ( class(dag), intent(in)  me,
character(len=*), intent(in), optional  rankdir,
integer, intent(in), optional  dpi,
character(len=*), intent(in), optional  edge 
)
private

Definition at line 293 of file dag_module.f90.

294 
295  implicit none
296 
297  class(dag),intent(in) :: me
298  character(len=:),allocatable :: str
299  character(len=*),intent(in),optional :: rankdir !! right to left orientation (e.g. 'RL')
300  integer,intent(in),optional :: dpi !! resolution (e.g. 300)
301  character(len=*),intent(in),optional :: edge !! right to left orientation (e.g. 'forward' or 'back)
302 
303  integer :: i,j !! counter
304  integer :: n_edges !! number of edges
305  character(len=:),allocatable :: attributes,label
306  logical :: has_label, has_attributes
307 
308  character(len=*),parameter :: tab = ' ' !! for indenting
309  character(len=*),parameter :: newline = new_line(' ') !! line break character
310 
311  if (me%n == 0) return
312 
313  str = 'digraph G {'//newline//newline
314  if (present(rankdir)) &
315  str = str//tab//'rankdir='//rankdir//newline//newline
316  if (present(dpi)) &
317  str = str//tab//'graph [ dpi = '//integer_to_string(dpi)//' ]'//newline//newline
318  if (present(edge)) &
319  str = str//tab//'edge [ dir = "'//trim(adjustl(edge))//'" ]'//newline//newline
320 
321  ! define the vertices:
322  do i=1,me%n
323  has_label = allocated(me%vertices(i)%label)
324  has_attributes = allocated(me%vertices(i)%attributes)
325  if (has_label) label = 'label="'//trim(adjustl(me%vertices(i)%label))//'"'
326  if (has_label .and. has_attributes) then
327  attributes = '['//trim(adjustl(me%vertices(i)%attributes))//','//label//']'
328  elseif (has_label .and. .not. has_attributes) then
329  attributes = '['//label//']'
330  elseif (.not. has_label .and. has_attributes) then
331  attributes = '['//trim(adjustl(me%vertices(i)%attributes))//']'
332  else ! neither
333  attributes = ''
334  end if
335  str = str//tab//integer_to_string(i)//' '//attributes//newline
336  if (i==me%n) str = str//newline
337  end do
338 
339  ! define the dependencies:
340  do i=1,me%n
341  if (allocated(me%vertices(i)%edges)) then
342  n_edges = size(me%vertices(i)%edges)
343  str = str//tab//integer_to_string(i)//' -> '
344  do j=1,n_edges
345  ! comma-separated list:
346  str = str//integer_to_string(me%vertices(i)%edges(j))
347  if (n_edges>1 .and. j<n_edges) str = str//','
348  end do
349  str = str//';'//newline
350  end if
351  end do
352 
353  str = str//newline//'}'
354 
Here is the call graph for this function:

◆ dag_get_dependencies()

pure integer function, dimension(:), allocatable dag_module::dag_get_dependencies ( class(dag), intent(in)  me,
integer, intent(in)  ivertex 
)
private

Definition at line 129 of file dag_module.f90.

130 
131  implicit none
132 
133  class(dag),intent(in) :: me
134  integer,intent(in) :: ivertex
135  integer,dimension(:),allocatable :: dep !! the set of all vertices
136  !! than depend on `ivertex`
137 
138  integer :: i !! vertex counter
139 
140  if (ivertex>0 .and. ivertex <= me%n) then
141 
142  ! have to check all the vertices:
143  do i=1, me%n
144  if (allocated(me%vertices(i)%edges)) then
145  if (any(me%vertices(i)%edges == ivertex)) then
146  if (allocated(dep)) then
147  dep = [dep, i] ! auto LHS allocation
148  else
149  dep = [i] ! auto LHS allocation
150  end if
151  end if
152  end if
153  end do
154 
155  end if
156 

◆ dag_get_edges()

pure integer function, dimension(:), allocatable dag_module::dag_get_edges ( class(dag), intent(in)  me,
integer, intent(in)  ivertex 
)
private

Definition at line 110 of file dag_module.f90.

111 
112  implicit none
113 
114  class(dag),intent(in) :: me
115  integer,intent(in) :: ivertex
116  integer,dimension(:),allocatable :: edges
117 
118  if (ivertex>0 .and. ivertex <= me%n) then
119  edges = me%vertices(ivertex)%edges ! auto LHS allocation
120  end if
121 

◆ dag_save_digraph()

subroutine dag_module::dag_save_digraph ( class(dag), intent(in)  me,
character(len=*), intent(in), optional  filename,
character(len=*), intent(in), optional  rankdir,
integer, intent(in), optional  dpi,
character(len=*), intent(in), optional  edge 
)
private

Definition at line 394 of file dag_module.f90.

395 
396  implicit none
397 
398  class(dag),intent(in) :: me
399  character(len=*),intent(in),optional :: filename !! file name for diagraph
400  character(len=*),intent(in),optional :: rankdir !! right to left orientation (e.g. 'RL')
401  integer,intent(in),optional :: dpi !! resolution (e.g. 300)
402  character(len=*),intent(in),optional :: edge !! right to left orientation (e.g. 'forward' or 'back)
403 
404  integer :: iunit, istat
405  character(len=:),allocatable :: diagraph
406 
407  diagraph = me%generate_digraph(rankdir,dpi,edge)
408 
409  open(newunit=iunit,file=filename,status='REPLACE',iostat=istat)
410 
411  if (istat==0) then
412  write(iunit,fmt='(A)',iostat=istat) diagraph
413  else
414  write(*,*) 'error opening '//trim(filename)
415  end if
416 
417  close(iunit,iostat=istat)
418 

◆ dag_set_edges()

subroutine dag_module::dag_set_edges ( class(dag), intent(inout)  me,
integer, intent(in)  ivertex,
integer, dimension(:), intent(in)  edges 
)
private

Definition at line 210 of file dag_module.f90.

211 
212  class(dag),intent(inout) :: me
213  integer,intent(in) :: ivertex !! vertex number
214  integer,dimension(:),intent(in) :: edges
215 
216  call me%vertices(ivertex)%set_edges(edges)
217 

◆ dag_set_vertex_info()

subroutine dag_module::dag_set_vertex_info ( class(dag), intent(inout)  me,
integer, intent(in)  ivertex,
character(len=*), intent(in), optional  label,
character(len=*), intent(in), optional  attributes 
)
private

Definition at line 182 of file dag_module.f90.

183 
184  class(dag),intent(inout) :: me
185  integer,intent(in) :: ivertex !! vertex number
186  character(len=*),intent(in),optional :: label !! if a label is not set,
187  !! then the integer vertex
188  !! number is used.
189  character(len=*),intent(in),optional :: attributes !! other attributes when
190  !! saving as a diagraph.
191 
192  if (present(label)) then
193  me%vertices(ivertex)%label = label
194  else
195  ! just use the vertex number
196  me%vertices(ivertex)%label = integer_to_string(ivertex)
197  end if
198 
199  if (present(attributes)) then
200  me%vertices(ivertex)%attributes = attributes
201  end if
202 
Here is the call graph for this function:

◆ dag_set_vertices()

subroutine dag_module::dag_set_vertices ( class(dag), intent(inout)  me,
integer, intent(in)  nvertices 
)
private

Definition at line 164 of file dag_module.f90.

165 
166  class(dag),intent(inout) :: me
167  integer,intent(in) :: nvertices !! number of vertices
168 
169  integer :: i
170 
171  me%n = nvertices
172  allocate(me%vertices(nvertices))
173  me%vertices%ivertex = [(i,i=1,nvertices)]
174 

◆ dag_toposort()

subroutine dag_module::dag_toposort ( class(dag), intent(inout)  me,
integer, dimension(:), intent(out), allocatable  order,
integer, intent(out)  istat 
)
private

Definition at line 225 of file dag_module.f90.

226 
227  class(dag),intent(inout) :: me
228  integer,dimension(:),allocatable,intent(out) :: order !! the toposort order
229  integer,intent(out) :: istat !! Status flag:
230  !!
231  !! * 0 if no errors
232  !! * -1 if circular dependency
233  !! (in this case, `order` will not be allocated)
234 
235  integer :: i,iorder
236 
237  if (me%n==0) return
238 
239  allocate(order(me%n))
240 
241  iorder = 0 ! index in order array
242  istat = 0 ! no errors so far
243  do i=1,me%n
244  if (.not. me%vertices(i)%marked) call dfs(me%vertices(i))
245  if (istat==-1) exit
246  end do
247 
248  if (istat==-1) deallocate(order)
249 
250  contains
251 
252  recursive subroutine dfs(v)
253 
254  !! depth-first graph traversal
255 
256  type(vertex),intent(inout) :: v
257  integer :: j
258 
259  if (istat==-1) return
260 
261  if (v%checking) then
262  ! error: circular dependency
263  istat = -1
264  else
265  if (.not. v%marked) then
266  v%checking = .true.
267  if (allocated(v%edges)) then
268  do j=1,size(v%edges)
269  call dfs(me%vertices(v%edges(j)))
270  if (istat==-1) return
271  end do
272  end if
273  v%checking = .false.
274  v%marked = .true.
275  iorder = iorder + 1
276  order(iorder) = v%ivertex
277  end if
278  end if
279 
280  end subroutine dfs
281 
recursive subroutine dfs(v)
Definition: dag_module.f90:253
Here is the call graph for this function:

◆ integer_to_string()

pure character(len=:) function, allocatable dag_module::integer_to_string ( integer, intent(in)  i)
private

Definition at line 426 of file dag_module.f90.

427 
428  implicit none
429 
430  integer,intent(in) :: i
431  character(len=:),allocatable :: s
432 
433  integer :: istat
434 
435  allocate( character(len=64) :: s ) ! should be big enough
436  write(s,fmt='(ss,I0)',iostat=istat) i
437  if (istat==0) then
438  s = trim(adjustl(s))
439  else
440  s = '***'
441  end if
442 
Here is the caller graph for this function:

◆ set_edge_vector()

subroutine dag_module::set_edge_vector ( class(vertex), intent(inout)  me,
integer, dimension(:), intent(in)  edges 
)
private

Definition at line 65 of file dag_module.f90.

66 
67  class(vertex),intent(inout) :: me
68  integer,dimension(:),intent(in) :: edges
69 
70  integer :: i !! counter
71 
72  if (allocated(me%edges)) then
73  do i=1,size(edges)
74  call me%add_edge(edges(i))
75  end do
76  else
77  allocate(me%edges(size(edges))) ! note: not checking for uniqueness here.
78  me%edges = edges
79  end if
80 
Here is the caller graph for this function: