Salome HOME
[EDF29576] : WIP
[modules/yacs.git] / src / yacsloader / driver_internal.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2024  CEA, EDF
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20
21 import salome
22 import logging
23
24 DisplayEntryInCMD = "--display"
25 VerboseEntryInCMD = "--verbose"
26 StopOnErrorEntryInCMD = "--stop-on-error"
27 DumpOnErrorEntryInCMD = "--dump-on-error"
28 DumpEntryInCMD = "--dump"
29 KernelTraceEntryInCMD = "--kerneltrace"
30 DumpStateEntryInCMD = "--dump-final"
31 LoadStateEntryInCMD = "--load-state"
32 SaveXMLSchemaEntryInCMD = "--save-xml-schema"
33 ShutdownEntryInCMD = "--shutdown"
34 ResetEntryInCMD = "--reset"
35 InitPortEntryInCMD = "--init-port"
36 DoNotSqueezeEntryInCMD = "--donotsqueeze"
37 IOREntryInCMD = "--ior-ns"
38
39 DisplayKeyInARGS = "display"
40 VerboseKeyInARGS = "verbose"
41 StopOnErrorKeyInARGS = "stop"
42 DumpOnErrorKeyInARGS = "dumpErrorFile"
43 DumpKeyInARGS = "dump"
44 KernelTraceKeyInARGS = "kerneltrace"
45 DumpStateKeyInARGS = "finalDump"
46 LoadStateKeyInARGS = "loadState"
47 SaveXMLSchemaKeyInARGS = "saveXMLSchema"
48 ShutdownKeyInARGS = "shutdown"
49 ResetKeyInARGS = "reset"
50 InitPortKeyInARGS = "init_port"
51 DoNotSqueezeKeyInARGS = "donotsqueeze"
52 IOREKeyInARGS = "iorNS"
53
54 my_runtime_yacs = None
55
56 my_ior_ns = None
57
58 def initializeSALOME():
59   import SALOMERuntime
60   global my_runtime_yacs
61   if my_runtime_yacs:
62     return
63   salome.salome_init()
64   if my_ior_ns:
65     salome.naming_service.DumpIORInFile( my_ior_ns )
66   flags = SALOMERuntime.RuntimeSALOME.UsePython + SALOMERuntime.RuntimeSALOME.UseCorba + SALOMERuntime.RuntimeSALOME.UseXml + SALOMERuntime.RuntimeSALOME.UseCpp + SALOMERuntime.RuntimeSALOME.UseSalome
67   SALOMERuntime.RuntimeSALOME.setRuntime( flags )
68   my_runtime_yacs = SALOMERuntime.getSALOMERuntime()
69   anIOR = salome.orb.object_to_string ( salome.modulcat )
70   aCatalog = my_runtime_yacs.loadCatalog( "session", anIOR )
71   my_runtime_yacs.addCatalog( aCatalog )
72
73 def SALOMEInitializationNeeded(func):
74   def decaratedFunc(*args,**kwargs):
75     initializeSALOME()
76     return func(*args,**kwargs)
77   return decaratedFunc
78
79 @SALOMEInitializationNeeded
80 def loadGraph( xmlFileName ):
81   """
82   Args:
83   -----
84   xmlFileName : XML file containing YACS schema
85
86   Returns
87   -------
88
89   SALOMERuntime.SalomeProc : YACS graph instance
90   """
91   import loader
92   l=loader.YACSLoader()
93   p=l.load( xmlFileName )
94   return p
95
96 def patchGraph( proc, squeezeMemory, initPorts, xmlSchema, loadStateXmlFile, reset, display):
97   """
98   Args:
99   -----
100
101   proc ( SALOMERuntime.SalomeProc ) : YACS Proc instance to be evaluated
102   squeezeMemory ( bool ) : squeezememory to be activated
103   initPorts (list<string>) : list of bloc.node.port=value.
104   xmlSchema (string) :
105   loadStateXmlFile (string) : file if any of state to be loaded inside proc
106   reset (int) : 
107   display (int) :
108   """
109   import SALOMERuntime
110   import loader
111   def parse_init_port(input):
112     """
113     Returns
114     -------
115     node, port, value
116     """
117     node_port, value = input.split("=")
118     nodePortSpl = node_port.split(".")
119     port = nodePortSpl[-1]
120     node = ".".join( nodePortSpl[:-1] )
121     return node,port,value
122       
123   if squeezeMemory:
124     logging.info("SqueezeMemory requested -> update proc")
125     allNodes = proc.getAllRecursiveNodes()
126     for node in allNodes:
127       if isinstance(proc,SALOMERuntime.PythonNode):
128         node.setSqueezeStatus( True )
129   #
130   for initPort in initPorts:
131       node,port,value = parse_init_port(initPort)
132       init_state = proc.setInPortValue(node, port, value)
133       if init_state != value:
134         raise RuntimeError(f"Error on initialization of {initPort}")
135   #
136   if xmlSchema:
137     SALOMERuntime.VisitorSaveSalomeSchemaUnsafe(proc,xmlSchema)
138     pass
139   #
140   if loadStateXmlFile:
141     loader.loadState( proc, loadStateXmlFile )
142     if reset > 0:
143       proc.resetState(reset)
144       proc.exUpdateState()
145   #
146   if display > 0:
147       proc.writeDotInFile("toto")
148          
149 @SALOMEInitializationNeeded
150 def prepareExecution(proc, isStop, dumpErrorFile):
151   """
152   Returns
153   -------
154
155   pilot.ExecutorSwig : Instance of executor
156   """
157   import pilot
158   ex=pilot.ExecutorSwig()
159   if isStop:
160     logging.info(f"Stop has been activated with {dumpErrorFile}")
161     ex.setStopOnError( dumpErrorFile!="", dumpErrorFile )
162   return ex
163
164 @SALOMEInitializationNeeded
165 def executeGraph( executor, xmlfilename, proc, dump, finalDump, display, shutdown ):
166   """
167   Args:
168   -----
169
170   executor (pilot.ExecutorSwig) : Executor in charge of evaluation.
171   proc ( SALOMERuntime.SalomeProc ) : YACS Proc instance to be evaluated
172   xmlfilename (string)
173   dump (int) : time interval between 2 dump state
174   finalDump ( string ) : filename containing final result of graph, if any.
175   display (int) :
176   shutdown (int) : shutdown level
177   """
178   import SALOMERuntime
179   dump_thread = None
180   import pilot
181   import os
182
183   if dump != 0:
184       dumpFile = "dumpState_{}".format( os.path.basename(xmlfilename) )
185       lockFile = "{}.lock".format( os.path.splitext( os.path.basename(xmlfilename) )[0] )
186       dump_thread = SALOMERuntime.ThreadDumpState(proc,dump,dumpFile,lockFile)
187       dump_thread.start()
188
189   executor.RunPy(proc,display,isPyThread=True,fromscratch=True) # same as RunW but releasing GIL
190   if proc.getEffectiveState() != pilot.DONE:
191     raise RuntimeError( proc.getErrorReport() )
192   #
193   if display > 0:
194       proc.writeDotInFile("titi")
195   #
196   if dump_thread:
197       dump_thread.join()
198   #
199   if finalDump:
200     logging.info(f"Final dump requested : {finalDump}")
201     SALOMERuntime.schemaSaveStateUnsafe( proc, finalDump )
202
203 @SALOMEInitializationNeeded
204 def destroyElementsGeneratedByExecutionOfGraph( proc, shutdown ):
205   """
206   Args:
207   -----
208
209   shutdown (int) : shutdown level
210
211   """
212   if shutdown < 999:
213     proc.shutdown(shutdown)
214   salome.dsm.shutdownScopes()
215   my_runtime_yacs.fini( False )
216
217 def toDict( args ):
218   """
219   Convert argparse.Namespace to dict
220   """
221   ATTR = ["display","verbose","stop","dumpErrorFile","dump","kerneltrace","finalDump","loadState","saveXMLSchema","shutdown","reset","init_port","donotsqueeze","iorNS"]
222   return {k:getattr(args,k) for k in ATTR}
223
224 def reprAfterArgParsing( args ):
225   """
226   Args:
227   -----
228
229   args (argparse.Namespace) : instance after parsing
230   """
231   return f"""
232 display : {args.display}
233 verbose : {args.verbose}
234 stop-on-error : {args.stop}
235 dump-on-error : "{args.dumpErrorFile}"
236 dump : {args.dump}
237 kerneltrace : {args.kerneltrace}
238 dump-final : {args.finalDump}
239 load-state : {args.loadState}
240 save-xml-schema : {args.saveXMLSchema}
241 shutdown : {args.shutdown}
242 reset : {args.reset}
243 init-port : {args.init_port}
244 donotsqueeze : {args.donotsqueeze}
245 iorNS : {args.iorNS}
246 """
247
248
249 def getArgumentParser():
250   import argparse
251   parser = argparse.ArgumentParser()
252   parser.add_argument('xmlfilename',help = "XML file containing YACS schema to be executed")
253   parser.add_argument("-d", DisplayEntryInCMD, dest = "display", type=int, default=[0], nargs=1, help="Display dot files: 0=never to 3=very often")
254   parser.add_argument("-v", VerboseEntryInCMD, dest = "verbose",help="Produce verbose output", action='store_true')
255   parser.add_argument("-s",StopOnErrorEntryInCMD,dest="stop",help="Stop on first error", action='store_true')
256   parser.add_argument("-e",DumpOnErrorEntryInCMD,dest="dumpErrorFile", type=str, const='dumpErrorState.xml', default="", nargs='?', help="Stop on first error and dump state")
257   parser.add_argument("-g",DumpEntryInCMD,dest="dump", type=int, const=60, default=0, nargs='?', help="dump state")
258   parser.add_argument("-kt", KernelTraceEntryInCMD, dest = "kerneltrace",help="Produce verbose of SALOME/KERNEL", action='store_true')
259   parser.add_argument("-f",DumpStateEntryInCMD, dest ="finalDump", type=str, const='finalDumpState.xml', default="", nargs='?', help="dump final state")
260   parser.add_argument("-l",LoadStateEntryInCMD, dest="loadState", type=str, default="", help="Load State from a previous partial execution")
261   parser.add_argument("-x",SaveXMLSchemaEntryInCMD, dest="saveXMLSchema", type=str, const="saveSchema.xml", nargs='?', default="", help = "dump xml schema")
262   parser.add_argument("-t",ShutdownEntryInCMD, dest = 'shutdown', type=int , default=1, help="Shutdown the schema: 0=no shutdown to 3=full shutdown")
263   parser.add_argument("-r",ResetEntryInCMD, dest = "reset", type=int , default = 0, help="Reset the schema before execution: 0=nothing, 1=reset error nodes to ready state")
264   parser.add_argument("-i",InitPortEntryInCMD, dest = 'init_port', type=str, default ="", help="Initialisation value of a port, specified as bloc.node.port=value.")
265   parser.add_argument("-z",DoNotSqueezeEntryInCMD = "--donotsqueeze", dest = "donotsqueeze", help = "Desactivate squeeze memory optimization.", action='store_true')
266   parser.add_argument(IOREntryInCMD, dest = "iorNS", type=str, default ="", help="file inside which the ior of NS will be stored")
267   return parser
268
269 def mainRun( args ):
270   global my_ior_ns
271   from salome_utils import positionVerbosityOfLoggerRegardingState,setVerboseLevel,setVerbose
272   args.display = args.display[0]
273   #
274   if args.iorNS:
275     my_ior_ns = args.iorNS
276   import pdb
277   pdb.set_trace()
278   #
279   if args.verbose:
280     setVerbose( args.kerneltrace )
281     setVerboseLevel(logging.INFO)
282     positionVerbosityOfLoggerRegardingState()
283     logging.info( reprAfterArgParsing(args) )
284   #
285   proc = loadGraph( args.xmlfilename )
286   patchGraph( proc, not args.donotsqueeze, [elt for elt in args.init_port.split(",") if elt !=""], args.saveXMLSchema, args.loadState, args.reset, args.display)
287   executor = prepareExecution( proc, args.stop, args.dumpErrorFile)
288   #
289   executeGraph( executor, args.xmlfilename, proc, args.dump, args.finalDump, args.display, args.shutdown)
290   #
291   destroyElementsGeneratedByExecutionOfGraph( proc, args.shutdown )
292
293
294 if __name__ == "__main__":
295   parser = getArgumentParser()
296   args = parser.parse_args()
297   mainRun( args )