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