File: cs_studymanager_graph.py

package info (click to toggle)
code-saturne 7.0.2%2Brepack-1~exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 62,868 kB
  • sloc: ansic: 395,271; f90: 100,755; python: 86,746; cpp: 6,227; makefile: 4,247; xml: 2,389; sh: 1,091; javascript: 69
file content (175 lines) | stat: -rw-r--r-- 6,668 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# -*- coding: utf-8 -*-

#-------------------------------------------------------------------------------

# This file is part of Code_Saturne, a general-purpose CFD tool.
#
# Copyright (C) 1998-2021 EDF S.A.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
# Street, Fifth Floor, Boston, MA 02110-1301, USA.

#-------------------------------------------------------------------------------

"""
This module contains the creation of the dependancy graph between CASES.

This module contains the following classes:
- node_case
- dependency_graph
"""

#-------------------------------------------------------------------------------
# Standard modules import
#-------------------------------------------------------------------------------

import os, sys
import logging

#-------------------------------------------------------------------------------
# Application modules import
#-------------------------------------------------------------------------------


#-------------------------------------------------------------------------------
# log config
#-------------------------------------------------------------------------------

logging.basicConfig()
log = logging.getLogger(__file__)
#log.setLevel(logging.DEBUG)
log.setLevel(logging.NOTSET)

#-------------------------------------------------------------------------------
# class node_case
#-------------------------------------------------------------------------------

class node_case:

    def __init__(self, name, n_procs, n_iter, estim_wtime, tags, depends):
        """ initializes a Code_Saturne CASE
        """
        # name should be in the folling form: STUDY/CASE/run_id
        # ex: "81_HEAD_LOSSES_COMPONENT/CASE_BEND/mesh12"
        self.name        = name
        self.n_procs     = n_procs
        self.tags        = tags
        # TODO: verify that these parameters are well handled by smgr in general
        self.n_iter      = n_iter
        # estimated wall time for the submission of the case on cluster
        self.estim_wtime = estim_wtime
        # depends should be in the same format as name
        self.depends     = depends
        # level is modified in add_node
        self.level       = None

    def __str__(self):
        res  = '\nCase ' + self.name
        res += ' on ' + str(self.n_procs) + ' procs'
        res += ' on ' + str(self.n_iter) + ' iterations'
        res += ' with an estimated wall time of ' + str(self.estim_wtime)
        res += ' with tags ' + str(self.tags)
        res += ' with level ' + str(self.level)

        return res

#-------------------------------------------------------------------------------
# class dependency_graph
#-------------------------------------------------------------------------------

class dependency_graph(object):

    def __init__(self):
        """ Initializes a dependency graph object to an empty dictionary
        """
        self.graph_dict = {}
        self.add_node(node_case('root', n_procs=0, n_iter=0, estim_wtime=0,
                                tags=None, depends=None))

    def add_dependency(self, dependency):
        """ Defines dependency between two node_cases as an edge in the graph
        """
        (node1, node2) = dependency
        if node1 in self.graph_dict:
            self.graph_dict[node1].append(node2)
        else:
            self.graph_dict[node1] = [node2]

    def add_node(self, node):
        """ Add a node_case in the graph if not already there.
            Add a dependency when depends parameters is defined
        """
        if node not in self.graph_dict:
            self.graph_dict[node] = []

            root_node = self.root_node()
            if node is not root_node:
                if node.depends:
                    for neighbor in self.graph_dict:
                        if neighbor.name == node.depends:
                            # cases with dependency are level > 1 and connected to the dependency
                            self.add_dependency((node, neighbor))
                            node.level = neighbor.level + 1
                            break
                    if node.level is None:
                        msg = "Problem in graph construction : dependency " \
                              + node.depends + " is not found.\n"
                        sys.exit(msg)
                else:
                    # cases with no dependency are level 1 and connected to the root node
                    self.add_dependency((node, root_node))
                    node.level = 1
            else:
                # root node is level 0 and have no dependency
                node.level = 0

    def nodes(self):
        """ returns the cases of the dependency graph """
        return list(self.graph_dict.keys())

    def dependencies(self):
        """ returns the dependencies between the cases of the graph """
        dependencies = []
        for node in self.graph_dict:
            for neighbor in self.graph_dict[node]:
                if (neighbor, node) not in dependencies:
                    dependencies.append((node, neighbor))
        return dependencies

    def extract_sub_graph(self, level, n_procs):
        """ extracts a sub_graph based on level and n_procs criteria"""
        sub_graph = dependency_graph()
        for node in self.graph_dict:
            if node.level == level and int(node.n_procs) == n_procs:
                sub_graph.add_node(node)
        return sub_graph

    def root_node(self):
        """ returns the root node of the graph """
        for node in self.graph_dict:
            if node.name == 'root':
                return node

    def __str__(self):
        res = "\nList of cases: "
        for node in self.nodes():
            res += str(node) + " "
        res += "\nList of dependencies: "
        for dependency in self.dependencies():
            (node1, node2) = dependency
            res += '\n' + str(node1.name) + ' depends on ' + str(node2.name)
        return res

#-------------------------------------------------------------------------------