1 # Copyright (C) 2011-2024 CEA, EDF
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # Lesser General Public License for more details.
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 # Author : Guillaume Boulant (EDF)
25 from medcalc.medcorba import factory
26 dataManager = factory.getDataManager()
27 calculator = factory.getCalculator()
29 # Some helper functions to deal with the fields and meshes
31 if sys.platform == "win32":
32 import MEDCouplingCompat as medcoupling
35 __mapTypeOfFieldLabel = {
36 medcoupling.ON_CELLS: "ON_CELLS",
37 medcoupling.ON_NODES: "ON_NODES",
38 medcoupling.ON_GAUSS_PT: "ON_GAUSS_PT",
39 medcoupling.ON_GAUSS_NE: "ON_GAUSS_NE"
42 def _typeOfFieldLabel(typeOfField):
43 # A field name could identify several MEDCoupling fields, that
44 # differ by their spatial discretization on the mesh (values on
45 # cells, values on nodes, ...). This spatial discretization is
46 # specified (at least) by the TypeOfField that is an integer value
53 return __mapTypeOfFieldLabel[typeOfField]
54 except IndexError as e:
58 def newFieldProxy(fieldHandlerId):
60 This creates a new FieldProxy wrapping the field whose
61 fieldHandlerId is passed in argument. The function requests the
62 DataManager to get the fieldHandler from its id.
64 fieldHandler = dataManager.getFieldHandler(fieldHandlerId)
65 return FieldProxy(fieldHandler)
68 # This define the map between attributes of a FieldProxy and those of
69 # the associated FieldHandler
70 PROXY_ATTRIBUTES_MAP = {"id":None,
76 "iteration":"iteration",
82 This object is a proxy to manipulate a remote MEDCoupling field
83 from within the SALOME python interpreter. Remote means that the
84 MEDCoupling field is in the SALOME container and not in the
85 client. See UserGuide class for detailed documentation of what can
86 be done with a field proxy.
88 def __init__( self, fieldHandler ):
90 This defines the wrapping on the field specified by its
93 self.__fieldHandler = fieldHandler
94 self.__restriction = None
95 from salome_utils import verbose
97 print(self.__repr__())
99 def __getattr__(self, name ):
101 This method realizes the read proxy pattern toward the field
104 # WRN: Note that the modification of this function can lead to
105 # coercion problem. Modify this function with extreme care.
106 return getattr( self.__fieldHandler, name )
108 def __setattr__(self, name, value):
110 This method realizes the write proxy pattern toward the field
111 handler. Only some attributes are writable. The list is
112 specified in the PROXY_ATTRIBUTES_MAP table.
114 if name in list(PROXY_ATTRIBUTES_MAP.keys()):
115 if PROXY_ATTRIBUTES_MAP[name] is not None:
116 medcalc.wrn("The modification of this attribute can't be done that way")
117 msg="Use f.update(%s=\"%s\") instead to ensure synchronisation of data."
118 medcalc.inf(msg%(PROXY_ATTRIBUTES_MAP[name],value))
120 medcalc.err("The modification of the attribute %s is not possible"%name)
122 self.__dict__[name] = value
126 Return a string containing a printable representation of this
127 object (what is displayed when typing the variable name and
130 # We need first to update the handler because some data can
131 # have changed (the meshid for example in case of change of
133 # __GBO__ : TODO check the performance
134 self.__fieldHandler = dataManager.getFieldHandler(self.id)
135 text = "field name (id)\t = %s (%s)\n"%(self.fieldname, self.id)
136 text+= "mesh name (id) \t = %s (%s)\n"%(self.meshname,self.meshid)
137 text+= "discretization \t = %s\n"%_typeOfFieldLabel(self.type)
138 text+= "(iter, order) \t = (%s,%s)\n"%(str(self.iteration),str(self.order))
139 text+= "data source \t = %s"%self.source
144 This is what is displayed when you type 'print(myField)'. Note
145 that this function prints the values of the field and then you
146 must be aware that a huge amount of data could be
147 displayed. Moreover, it means that this operation triggers the
148 loading of the associated MEDCouplingFied data in the SALOME
151 text = dataManager.getFieldRepresentation(self.id)
154 def __add__(self, operande):
156 This makes the addition of two fields or the addition of a
157 scalar to a field. It depends weither the operande is a
158 FieldProxy or a simple scalar numerical value.
160 # The medcalc calculator could raise exceptions coming from
161 # MEDCoupling. Note that the fieldproxy instances are used
162 # from within the python console, and for ergonomic reason, we
163 # choose to not raise the possible exceptions to the console
164 # by a clear message. Keep this in mind for unit test. You
165 # have to test the return value, which should not be
166 # null. This principle is applied for all operations.
168 if isinstance(operande, FieldProxy):
169 # The operande is an other field
170 medcalc.inf("Addition of %s and %s"%(self.fieldname, operande.fieldname))
171 rfieldHandler = calculator.add(self.__fieldHandler, operande.__fieldHandler)
173 # The operande is a scalar numerical value that must be
174 # considered as an offset in a linear transformation
177 medcalc.inf("Application of the offset %s to %s" % (offset, self.fieldname))
178 rfieldHandler = calculator.lin(self.__fieldHandler, factor, offset)
179 except SALOME.SALOME_Exception as ex:
180 medcalc.err(ex.details.text)
183 return FieldProxy(rfieldHandler)
185 def __radd__(self, operande):
187 The user typed 'operande+self', we replace by 'self+operande'
188 to automatically activate the __add__ method of fieldpoxy.
192 def __iadd__(self, operande):
194 These methods implements the augmented arithmetic assignments (+=)
196 medcalc.wrn("NOT IMPLEMENTED YET")
198 def __sub__(self,operande):
200 This makes the substraction of two fields or the substraction
201 of a scalar to a field. It depends weither the operande is a
202 FieldProxy or a simple scalar numerical value.
205 if isinstance(operande, FieldProxy):
206 # The operande is an other field
207 medcalc.inf("Substraction of %s by %s"%(self.fieldname, operande.fieldname))
208 rfieldHandler = calculator.sub(self.__fieldHandler, operande.__fieldHandler)
210 # The operande is a scalar numerical value that must be
211 # considered as an offset in a linear transformation
214 medcalc.inf("Application of the offset %s to %s" % (offset, self.fieldname))
215 rfieldHandler = calculator.lin(self.__fieldHandler, factor, offset)
216 except SALOME.SALOME_Exception as ex:
217 medcalc.err(ex.details.text)
220 return FieldProxy(rfieldHandler)
222 def __rsub__(self, operande):
224 The user typed 'operande-self' where operande is not a field
225 proxy. This function process the situation.
227 # The operande is a numerical value (because otherwise, the
228 # "sub" method would have been called instead). We may apply
229 # the command '(self-operande)*(-1)' to activate the __sub__
230 # method of fieldpoxy.
232 #return (self-operande)*(-1)
234 # We prefer to apply a linear transformation because it can be
235 # done in one single request to the med calculator.
239 medcalc.inf("Linear transformation %s%s*%s" % (offset, factor, self.fieldname))
241 rfieldHandler = calculator.lin(self.__fieldHandler, factor, offset)
242 except SALOME.SALOME_Exception as ex:
243 medcalc.err(ex.details.text)
246 return FieldProxy(rfieldHandler)
248 def __mul__(self, operande):
250 This makes the multiplication of two fields or the
251 multiplication of a scalar to a field. It depends weither the
252 operande is a FieldProxy or a simple scalar numerical value.
255 if isinstance(operande, FieldProxy):
256 # The operande is an other field
257 medcalc.inf("Multiplication of %s by %s"%(self.fieldname, operande.fieldname))
258 rfieldHandler = calculator.mul(self.__fieldHandler, operande.__fieldHandler)
260 # The operande is a scalar numerical value that must be
261 # considered as an offset in a linear transformation
264 medcalc.inf("Scaling %s by factor %s" % (self.fieldname, factor))
265 rfieldHandler = calculator.lin(self.__fieldHandler, factor, offset)
266 except SALOME.SALOME_Exception as ex:
267 medcalc.err(ex.details.text)
270 return FieldProxy(rfieldHandler)
272 def __rmul__(self, operande):
274 The user typed 'operande*self', we want to execute
275 'self*operande' to activate the __mul__ method of fieldpoxy.
279 def __div__(self, operande):
281 This makes the division of two fields or the division of field
282 by a scalar. It depends weither the operande is a FieldProxy
283 or a simple scalar numerical value.
286 if isinstance(operande, FieldProxy):
287 # The operande is an other field
288 medcalc.inf("Division of %s by %s"%(self.fieldname, operande.fieldname))
289 rfieldHandler = calculator.div(self.__fieldHandler, operande.__fieldHandler)
291 # The operande is a scalar numerical value that must be
292 # considered as an offset in a linear transformation
295 medcalc.inf("Scaling %s by factor 1/%s" % (self.fieldname, operande))
296 rfieldHandler = calculator.lin(self.__fieldHandler, factor, offset)
297 except SALOME.SALOME_Exception as ex:
298 medcalc.err(ex.details.text)
301 return FieldProxy(rfieldHandler)
303 def __rdiv__(self, operande):
305 The user typed 'operande/self', we want to execute for each
306 value of the field the operation 'operande/value'.
308 medcalc.inf("Division of %s by %s" % (operande, self.fieldname))
309 function = "%s/u"%operande
310 nbResComp = MEDCALC.NBCOMP_DEFAULT
312 rfieldHandler = calculator.fct(self.__fieldHandler,function,nbResComp)
313 except SALOME.SALOME_Exception as ex:
314 medcalc.err(ex.details.text)
317 return FieldProxy(rfieldHandler)
319 def __pow__(self, power):
321 This compute the power of the field to the specified value.
323 function = "abs(u)^%s"%power
324 return self.ope(function,duplicate=True)
328 This compute the absolute value of the field. We use here
330 return self.ope(function="abs(u)",duplicate=True)
334 This computes the negative of this field (when you type -f)
340 This creates a duplicate of the field. The whole data are
343 medcalc.inf("Duplication of %s"%self.fieldname)
345 rfieldHandler = calculator.dup(self.__fieldHandler)
346 except SALOME.SALOME_Exception as ex:
347 medcalc.err(ex.details.text)
350 return FieldProxy(rfieldHandler)
352 def ope(self, function, duplicate=True):
354 This can be used to apply a transformation function to this
355 field. The transformation is specified using a literal
356 equation given as a string where u stands for the field.
358 # _GBO_ TO BE IMPLEMENTED: the case where duplicate = False
359 # must modify the object itself and not create a new field
360 medcalc.inf("Operate the equation \"%s\" to %s"%(function,self.fieldname))
362 rfieldHandler = calculator.fct(self.__fieldHandler,
364 MEDCALC.NBCOMP_DEFAULT)
365 except SALOME.SALOME_Exception as ex:
366 medcalc.err(ex.details.text)
369 return FieldProxy(rfieldHandler)
371 def __call__(self, restriction=None):
373 This could be used to return a fieldproxy binded on the same
374 fieldHandler than self, but with options that restrict the
375 usage to a domain specified by the given arguments (restricted
376 to a component, to a part of the mesh, ...).
378 medcalc.wrn("Not implemented yet. Return the field itself")
379 self.__restriction = restriction
382 def update(self,name=None,iteration=None,order=None,source=None):
384 This function can be used to update the meta-data associated
385 to this field. It can modify the name, the iteration, the
386 order and the source.
389 name = self.fieldname
390 if iteration is None:
391 iteration = self.iteration
397 dataManager.updateFieldMetadata(self.id,name,iteration,order,source)
398 self.__fieldHandler.fieldname = name
399 self.__fieldHandler.iteration = iteration
400 self.__fieldHandler.order = order
401 self.__fieldHandler.source = source
402 # WARN: Note that you have to update directly the fieldHandler
403 # object because of the presence of the method __setattr__
404 # that make the proxy to this update method
406 # Finally, we have to notify the GUI for update of field prestations
407 #self.__notifyGui_update()
408 from medcalc.medevents import notifyGui_updateField
409 notifyGui_updateField(self.id)
411 # Print for visual control
412 from salome_utils import verbose
414 print(self.__repr__())
419 # ===================================================================
420 # unit test functions
421 # ===================================================================
424 def TEST_typeOfFieldLabel():
425 print(typeOfFieldLabel(0))
426 print(typeOfFieldLabel(5))
429 # ===================================================================
430 if __name__ == "__main__":
431 TEST_typeOfFieldLabel()