.. _code-index: .. sectionauthor:: Gregor Simič Python interface ---------------- SMITER Python interface classes are used for storing input data and parameters. .. note:: GUI provides :guilabel:`Python view` editor that can be used for editing scripts. The editor can be opened by :kbd:`Alt+Y` or through :menuselection:`Window --> N&ew Window --> Python view`. Python scripts can then be loaded by :menuselection:`F&ile --> Load script` or :kbd:`Ctrl+T`. Classes :py:mod:`powcal`, :py:mod:`hdsgen` and :py:mod:`geoq` all contain default parameters and functions for retrieving and editing the parameters. Every function also has the function :py:func:`createCTL` function for writing the parameters in a ``FORTRAN`` namelist file. The class :py:mod:`geoq` is used for storing the information about the mesh used when computing a SMITER case. For convenience it contains a function that writes a mesh in ``VTK`` format. For each mesh used in a SMITER computation, a type has to be specified: whether the mesh is used as ``wall``, ``target`` or ``shadow``. The class :py:mod:`eqdsk` is used for saving the plasma ``equilibrium`` data. The function :py:meth:`EQDSK.eqdsk.readEQDSKstring` reads the ``G EQDSK`` format and saves all the quantities in attributes. For visualization there are functions that returns array in correct units (meter) for plotting or creating geometry/mesh objects. The class :py:mod:`SMITERcase` is used as a glue for the previous mentioned to form a SMITER case. It contains set and get functions for each required input object. The function :py:meth:`case.SMITERcase.setInputParameters` function properly sets the input parameters of objects that require output or input data from other objects in the same case. The class :py:mod:`SMITER_API.ComputeCase` runs the calculation by preparing a run directory with the input data from the :py:mod:`SMITERcase` and running the SMARDDA executables to perform the calculation. POWCAL ~~~~~~ :py:mod:`powcal` contains the parameters for the SMARDDA module ``powcal``. The parameters of a POWCAL object can be set with the function :py:meth:`POWCAL.setVariable` and retrieved by :py:meth:`POWCAL.getVariable`. Example of usage: .. code-block:: python import powcal x = powcal.POWCAL('nameOfObject') x.setVariable('power_loss', '7.5e+06') x.getVariable('power_loss') # Prints 7.5e+06 x.createCTL() # Prints the string of the CTL input file. .. autoclass:: SMITER.POWCAL :inherited-members: Base GEOQ ~~~~ :py:mod:`GEOQ` is used for storing information about which mesh in SMITER is used as input data and for setting parameters for running the computation Example of usage: .. code-block:: python import geoq x = geoq.GEOQ(name='name of mesh', type='type of usage in smiter case') # The name and type keywords are not necessary, you can still create the # object as x = geoq.GEOQ() # Then set the name of the mesh and type with the following functions x.setName('name of mesh in SALOME') x.setMeshEntry('entry of mesh in the study') x.setType('wall or shadow or target') # Each have different default parameter values. # Same functions to set or get variables as in powcal.POWCAL x.setVariable('parameter', 'value') x.getVariable('parameter') x.createCTL() # To create the CTL input file. # SMARDDA GEOQ requires mesh in the form of a VTK file. So geoq.GEOQ # contains the createVTK function. # Get the mesh object import salome from salome.smesh import smeshBuilder sb = smeshBuilder.New() # Get the study entry from the GEOQ x object. meshSalomeObject = salome.myStudy.FindObjectID(x.getMeshEntry()) # Fetch the mesh data from the meshSalomeObject meshObject = meshSalomeObject.GetObject() x.createVTK(meshObject) # Prints the contents of the mesh in VTK format. .. autoclass:: SMITER.GEOQ :inherited-members: Base HDSGEN ~~~~~~ :py:mod:`HDSGEN` contains parameters for SMARDDA module ``hdsgen``. Example of usage: .. code-block:: python import hdsgen x = hdsgen.HDSGEN('nameOfObject') x.setVariable('limit_geobj_in_bin', '2000') x.getVariable('limit_geobj_in_bin') # Prints 2000 x.createCTL() # Prints the string of the CTL input file. .. autoclass:: SMITER.HDSGEN :inherited-members: Base EQDSK ~~~~~ :py:mod:`EQDSK` is a module for reading ``EQDSK G`` files. It parses all the quantities in the ``EQDSK G`` which are then accessible through the attributes of the module, described bellow. An example is also written into the file on how to use the module. .. note:: This module can be used standalone if you remove the ``SMITER_ORB__POA.EQDSK`` from the inheritance in the class definition. .. autoclass:: SMITER.EQDSK SMITERCase ~~~~~~~~~~ :py:mod:`SMITERcase` is a glue for all the previous objects, which together creates a SMITER case. An example of empty objects: .. code-block:: python import geoq import hdsgen import powcal import eqdsk target = geoq.GEOQ('targetName', 'target') wall = geoq.GEOQ('wallNme', 'wall') shadow = geoq.GEOQ('shadowName', 'shadow') hdsgen = hdsgen.HDSGEN('hdsgenName') powcal = powcal.POWCAL('powcalName') eq = eqdsk.EQDSK('eqdskName') import case x = case.SMITERcase('caseName') x.setWall(wall._this()) x.setTarget(target._this()) x.setShadow(shadow._this()) x.setHDSGEN(hdsgen._this()) x.setPOWCAL(powcal._this()) x.setEQDSK(eqdsk._this()) # The following function sets the parameters of objects which needs output # or input data from other objects. (i.e., POWCAL requires the input mesh # of TARGET GEOQ) x.setInputParameters() .. autoclass:: SMITER.CASE :inherited-members: Base SMITER_API ~~~~~~~~~~ :py:mod:`ComputeCase` starts the computation of the SMITER case. It requires a SMITER case object and settings such as SMITER directory location. The following example typed in Python console inside SMITER GUI works when Smiter module is activated and case is selected by mouse in :guilabel:`Object Browser`. Case can then be computed with all settings active. .. code-block:: python >>> import SMITERGUI >>> case = SMITERGUI.getComputeObject() >>> case.compute() To change a parameter in a loop use the following non-blocking script that calls ``loop()`` when computation finishes. This is done by connecting signal. .. code-block:: python import os import SMITERGUI from salome.gui import dockwidgets pythonDock = dockwidgets.findDockWidgetByTitle('Python Console') batch = SMITERGUI.getComputeObject() global count count = 0 def console_print(text): pythonDock.widget().layout().itemAt(0).widget().append(text + '\n') def loop(): global count, batch, os powcalPath = os.path.join(batch.caseDirectory, batch.smiterCase.getName(), 'P', 'Powcal_powx') os.rename(powcalPath + '.vtk', powcalPath + str(count) + '.vtk') powerLoss = (1 + count) * 1e6 batch.smiterCase.getPOWCAL().setVariable('power_loss', '%d' % powerLoss) count += 1 if count < 3: console_print('count = ' + str(count)) batch.computePOWCAL() else: batch.caseComputeFinished.disconnect() console_print("Open the resulting VTK files in %s/%s/P directory." % (batch.caseDirectory, batch.smiterCase.getName())) batch.caseComputeFinished.connect(loop) print("Computing complete case and then loop POWCAL ...") batch.compute() SMITER_BATCH_API ~~~~~~~~~~~~~~~~ SMITER_BATCH_API is a main module that does not use PyQt5 modules or any GUI modules, to access SMITER functionality without active X11 connection, for running in cluster batch submission queues. The following example script runs an already prepared study file from deck examples under directory pointed by environment variable ``SMITER_STUDY_EXAMPLES_DIR``. .. code-block:: python import salome import SMITER_BATCH_API import SMITER_utils import sys import os # Path to the study file, in this case absolute. studyFileName = os.path.join(os.getenv('SMITER_STUDY_EXAMPLES_DIR'), 'deck', 'Test-EQ3-inrshad1-inres1.hdf') # Open and initialize the study. salome.salome_init(studyFileName) # Activate module SMITER and activate CORBA SMITER_utils.activateSmiterModule(salome.myStudy) # Get the list of cases in the study file. listOfCaseNames = SMITER_BATCH_API.getAvailableCases() print('List of cases: ', listOfCaseNames) caseName = listOfCaseNames[0] print("Creating compute instance.") batch = SMITER_BATCH_API.ComputeCase() # Create the compute case instance. batch.setSmiterDir(os.getenv('SMITER_DIR', os.path.expanduser('~/smiter'))) batch.setCaseDir(os.getenv('HOME')) print("Setting case") batch.findAndSetCase(caseName) print("Starting compute") batch.compute() print("Open the resulting VTK file %s/P/Powcal_powx.vtk in ParaView." % batch.caseDirectory) .. automodule:: SMITER_BATCH_API :members: ComputeCase .. py:module:: ComputeCase .. _base_dialog: SMITER dialog ~~~~~~~~~~~~~ This is a base class for writing simple dialogs. .. automodule:: base_dialog :members: Dialog .. py:module:: Dialog Getting objects from objects browser via python console ------------------------------------------------------- For inspecting certain objects there is a quick way of getting the object in the python terminal via salome session:: >>> # First select an object by clicking on it in the object browser >>> import salome >>> o = salome.myStudy.FindObjectID(salome.sg.getSelected(0)) The *salome.myStudy* contains functions for searching objects, either by `name` or its ``entry``. Since ``entries`` are unique, it is better to programmatically get the ``object`` we want via its ``entry`` and not by its ``name``. The function *salome.sg.getSelected(0)* returns the first selected or highlighted object from the ``object browser``. For convenience there is also a **salome.sg.getAllSelected** which returns a list of entries for all selected ``objects`` in the ``object manager``. Salome Object or SObject attributes ----------------------------------- **Attributes** are containers for data or visual settings for objects in the ``objects manager``. An `SObject` can contain the following list of attributes: **AttributeName** Attribute that has the name of the object stored. **AttributeString** Attribute for storing a string. **AttributePixMap** Attribute that has the name of the .png icon stored. You can see the names of the icons if you go to the resource folder of the module source code. If the string name for the PixMap is correct, a new icon should be seen besides the object in the objects manager. **AttributeParameter** This is a container for dictionaries for almost all types. Integers, Reals, Strings, Integer arrays, Real arrays, String array... For storing various data in an object this is the way to go, since you need fewer lines of codes and is thus better to read. There are other attributes, so for more reading, go to SALOME documentation. The section is called **SALOME KERNEL Developer Documentation**. Assigning attributes to an object --------------------------------- In SALOME every `Salome object` or **SObject** have a set of attributes. You have integer or real attribute, then sequence of reals or integers, etc. To assign attributes to these attributes there are several ways. The first way is only for attributes that have string values [AttributeName, AttributePixMap, AttributeString,...]. Objects have a method called **SetAttrString**:: >>> # First you have to get a handle to an object by using the previous >>> # howto on getting object from object browser >>> import salome >>> # Select an object in the object browser by clicking it, resulting a >>> # highlight on the object >>> o = salome.myStudy.FindObjectID(salome.sg.getSelected(0)) >>> # If the previous name was i.e. "case1" we can change it by >>> o.SetAttrString('AttributeName', "new_name") >>> # Then the objects browser needs to be visually updated by >>> salome.sg.updateObjBrowser() >>> # The new name "new_name" should be visible in the objects browser The second way is using the study builder to find or create attributes for an object, with the **FindOrCreateAttribute** method:: >>> import salome >>> b = salome.myStudy.NewBuilder() >>> # Click on an object in the objects browser >>> o = salome.myStudy.FindObjectID(salome.sg.getSelected(0)) >>> # Find the attribute and get the handle to it >>> name_attribute = b.FindOrCreateAttribute(o, 'AttributeName') >>> # We get an object, which has a get and set method. >>> name_attribute.SetValue('new_name') >>> # Update objects browser >>> salome.sg.updateObjBrowser() >>> # To get the value storred in the object >>> value = name_attribute.Value() .. note:: Attributes, as in types, do not have the same names for set and get methods The third way is finding attributes from salome objects, by using the **FindAttribute** method:: >>> import salome >>> o = salome.myStudy.FindObjectID(salome.sg.getSelected(0)) >>> status, name_attribute = o.FindAttribute('AttributeName') >>> # If the attribute exists then the status, which is a boolean will be >>> # true, otherwise it will be false. >>> if status: >>> name_attribute.SetValue('new_name') >>> salome.sg.updateObjBrowser() With this way, you cannot create attributes, you can only find them in an object if the object contains it. Attribute parameter ------------------- Since this attribute contains dictionaries for different types, there is a separate section for it. First we get the attribute parameter from the object:: >>> import salome >>> b = salome.myStudy.NewBuilder() >>> o = salome.myStudy.FindObjectID(salome.sg.getSelected(0)) >>> attribute = b.FindOrCreateAttribute(o, 'AttributeParameter') >>> # If you wish to assign a value, you assign it as a pair of >>> # (key, value) >>> # For example with the usage of SetInt >>> attribute.SetInt('a', 5) >>> # Now if we wish to get the value we use the GetInt method >>> attribute.GetInt('a') 5 >>> # One important rule is that you should first check if there actually is >>> # an integer value stored under the key 'a'. To get an array of keys , >>> # for example, integers, use the method GetID( enumerator ) >>> # The enumerator for int is 0 >>> attribute.GetIDs(0) ['a'] >>> # Other enumerators are: >>> # 0 for integer, 1 for real, 2 for boolean, 3 for string, >>> # 4 for real array, 5 for integer array, 6 for string array For more informations read the **SALOME KERNEL Developer Documentation**.