Salome HOME
[MEDCalc] Support for ELNO field + minor GUI bug fix.
[modules/med.git] / src / MEDCalc / cmp / MEDPresentation.cxx
1 // Copyright (C) 2011-2016  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Authors: A Bruneton (CEA), C Aguerre (EdF)
20
21 #include "MEDPyLockWrapper.hxx"
22 #include "MEDFactoryClient.hxx"
23 #include "MEDPresentation.hxx"
24 #include "MEDPresentationException.hxx"
25 #include "MEDCouplingRefCountObject.hxx"
26 #include <SALOME_KernelServices.hxx>
27 #undef LOG
28 #include <Basics_Utils.hxx>
29
30 #include <sstream>
31
32 const std::string MEDPresentation::PROP_NAME  = "name";
33 const std::string MEDPresentation::PROP_NB_COMPONENTS = "nbComponents";
34 const std::string MEDPresentation::PROP_SELECTED_COMPONENT = "selectedComponent";
35 const std::string MEDPresentation::PROP_COMPONENT = "component_";
36 const std::string MEDPresentation::PROP_COLOR_MAP = "colorMap";
37 const std::string MEDPresentation::PROP_SCALAR_BAR_RANGE = "scalarBarRange";
38
39 MEDPresentation::MEDPresentation(MEDPresentation::TypeID fieldHandlerId, const std::string& name,
40                                  const MEDCALC::ViewModeType viewMode,
41                                  const MEDCALC::ColorMapType colorMap,
42                                  const MEDCALC::ScalarBarRangeType sbRange)
43     : _fieldHandlerId(fieldHandlerId), _propertiesStr(),
44       //_pipeline(0), _display(0)
45       _selectedComponentIndex(-1),
46       _viewMode(viewMode),
47       _colorMap(colorMap),
48       _sbRange(sbRange),
49       _renderViewPyId(-1),  // will be set by getRenderViewCommand()
50       _globalDict(0)
51 {
52   MEDCALC::MEDDataManager_ptr dataManager(MEDFactoryClient::getDataManager());
53   MEDCALC::FieldHandler* fieldHandler = dataManager->getFieldHandler(fieldHandlerId);
54   MEDCALC::MeshHandler* meshHandler = dataManager->getMesh(fieldHandler->meshid);
55   MEDCALC::DatasourceHandler* dataSHandler = dataManager->getDatasourceHandlerFromID(meshHandler->sourceid);
56
57   _fileName = dataSHandler->uri;
58   _fieldName = fieldHandler->fieldname;
59   _mcFieldType = (MEDCoupling::TypeOfField) fieldHandler->type;
60   _pvFieldType = getPVFieldTypeString(_mcFieldType);
61   _meshName = meshHandler->name;
62
63   if (_fileName.substr(0, 7) != std::string("file://")) {
64     const char* msg = "MEDPresentation(): Data source is not a file! Can not proceed.";
65     STDLOG(msg);
66     throw MEDPresentationException(msg);
67   }
68   _fileName = _fileName.substr(7, _fileName.size());
69
70   setStringProperty(MEDPresentation::PROP_NAME, name);
71
72   setIntProperty(MEDPresentation::PROP_NB_COMPONENTS, 0);
73   setIntProperty(MEDPresentation::PROP_SELECTED_COMPONENT, 0);
74
75   setIntProperty(MEDPresentation::PROP_COLOR_MAP, static_cast<int>(colorMap));
76   setIntProperty(MEDPresentation::PROP_SCALAR_BAR_RANGE, static_cast<int>(sbRange));
77
78   // Python variables:
79   int id = GeneratePythonId();
80   std::ostringstream oss_o, oss_d, oss_l, oss_s, oss_r;
81   oss_o << "__obj" << id;
82   oss_s << "__srcObj" << id;
83   oss_d << "__disp" << id;
84   oss_l << "__lut" << id;
85   oss_r << "__range" << id;
86   _objVar = oss_o.str();
87   _srcObjVar = oss_s.str();
88   _dispVar = oss_d.str();
89   _lutVar = oss_l.str();
90   _rangeVar = oss_r.str();
91 }
92
93 MEDPresentation::~MEDPresentation()
94 {
95   STDLOG("~MEDPresentation(): clear display");
96   {
97     MEDPyLockWrapper lock;
98     std::ostringstream oss_v, oss;
99     oss_v << "__view" << _renderViewPyId;
100     oss << "pvs.Hide(" << _objVar <<  ", view=" << oss_v.str() << ");";
101     oss << "pvs.Render();";
102
103     PyRun_SimpleString(oss.str().c_str());
104   }
105 }
106
107 void
108 MEDPresentation::generatePipeline()
109 {
110   // Might be more complicated in the future:
111
112   this->internalGeneratePipeline();
113 }
114
115 //void
116 //MEDPresentation::pushPyObjects(PyObjectId obj, PyObjectId disp)
117 //{
118 //  _pipeline.push_back(obj);
119 //  _display.push_back(disp);
120 //}
121
122 void
123 MEDPresentation::pushAndExecPyLine(const std::string & lin)
124 {
125   execPyLine(lin);
126   _pythonCmds.push_back(lin);
127 }
128
129 void
130 MEDPresentation::execPyLine(const std::string & lin)
131 {
132   MEDPyLockWrapper lock;
133   STDLOG("@@@@ MEDPresentation::execPyLine() about to exec >> " << lin);
134   if(PyRun_SimpleString(lin.c_str()))
135     {
136       std::ostringstream oss;
137       oss << "MEDPresentation::execPyLine(): following Python command failed!\n";
138       oss << ">> " << lin;
139       STDLOG(oss.str());
140       throw KERNEL::createSalomeException(oss.str().c_str());
141     }
142 }
143
144 void
145 MEDPresentation::setStringProperty(const std::string& propName, const std::string& propValue)
146 {
147   _propertiesStr[propName] = propValue;
148 }
149
150 const std::string
151 MEDPresentation::getStringProperty(const std::string& propName) const
152 {
153   std::map<std::string, std::string>::const_iterator it = _propertiesStr.find(propName);
154   if (it != _propertiesStr.end()) {
155       return (*it).second;
156   }
157   else {
158       STDLOG("MEDPresentation::getStringProperty(): no property named " + propName);
159       throw MEDPresentationException("MEDPresentation::getStringProperty(): no property named " + propName);
160   }
161 }
162
163 void
164 MEDPresentation::setIntProperty(const std::string& propName, const int propValue)
165 {
166   _propertiesInt[propName] = propValue;
167 }
168
169 int
170 MEDPresentation::getIntProperty(const std::string& propName) const
171 {
172   std::map<std::string, int>::const_iterator it = _propertiesInt.find(propName);
173   if (it != _propertiesInt.end()) {
174       return (*it).second;
175   }
176   else {
177       STDLOG("MEDPresentation::getIntProperty(): no property named " + propName);
178       throw MEDPresentationException("MEDPresentation::getIntProperty(): no property named " + propName);
179   }
180 }
181
182  void
183  MEDPresentation::dumpIntProperties() const
184  {
185    std::map<std::string, int>::const_iterator it = _propertiesInt.begin();
186    STDLOG("@@@ Dumping INT properties");
187    for(; it != _propertiesInt.end(); ++it)
188      {
189        std::ostringstream oss;
190        oss << (*it).first << "  ->   " << (*it).second;
191        STDLOG(oss.str());
192      }
193  }
194
195  void
196  MEDPresentation::dumpStringProperties() const
197  {
198    std::map<std::string, std::string>::const_iterator it = _propertiesStr.begin();
199    STDLOG("@@@ Dumping STR properties");
200    for(; it != _propertiesStr.end(); ++it)
201      {
202        std::ostringstream oss;
203        oss << (*it).first << "  ->   " << (*it).second;
204        STDLOG(oss.str());
205      }
206  }
207
208  void
209  MEDPresentation::internalGeneratePipeline()
210  {
211    MEDPyLockWrapper lock;
212    pushAndExecPyLine( "import pvsimple as pvs;");
213    pushAndExecPyLine( "import medcalc");
214  }
215
216
217 /**
218 * @return a borrowed reference. Do not DECRREF!
219 */
220 PyObject*
221 MEDPresentation::getPythonObjectFromMain(const char* python_var) const
222 {
223   if (! _globalDict)
224     {
225       // All the calls below returns *borrowed* references
226       PyObject* main_module = PyImport_AddModule((char*)"__main__");
227       _globalDict = PyModule_GetDict(main_module);
228     }
229   return PyDict_GetItemString(_globalDict, python_var);
230 }
231
232 std::string
233 MEDPresentation::getPVFieldTypeString(MEDCoupling::TypeOfField fieldType) const
234 {
235   switch(fieldType)
236   {
237     case MEDCoupling::ON_CELLS:
238       return "CELLS";
239     case MEDCoupling::ON_NODES:
240       return "POINTS";
241     case MEDCoupling::ON_GAUSS_PT:
242       return "POINTS"; // because internally after application of the ELGA filter, the field will appear as a POINT field
243     case MEDCoupling::ON_GAUSS_NE:
244       return "POINTS"; // because internally after application of the ELNO mesh filter, the field will appear as a POINT field
245     default:
246       STDLOG("MEDPresentation::getPVFieldTypeString() -- Not implemented ! ELNO field?");
247       return "";
248   }
249 }
250
251 std::string
252 MEDPresentation::getRenderViewVar() const
253 {
254   std::ostringstream oss;
255   oss << "__view" << _renderViewPyId;
256   return oss.str();
257 }
258
259 /*!
260  * Creates the MEDReader source in the pipeline, and potentially apply GAUSS/ELNO filters.
261  */
262 void
263 MEDPresentation::createSource()
264 {
265   std::string typ;
266   switch(_mcFieldType) {
267     case MEDCoupling::ON_CELLS: typ = "P0"; break;
268     case MEDCoupling::ON_NODES: typ = "P1"; break;
269     case MEDCoupling::ON_GAUSS_PT: typ = "GAUSS"; break;
270     case MEDCoupling::ON_GAUSS_NE: typ = "GSSNE"; break;
271     default:
272       const char * msg ="MEDPresentation::createSource(): field type not impl. yet!";
273       STDLOG(msg);
274       throw KERNEL::createSalomeException(msg);
275   }
276
277   std::ostringstream oss;
278   oss << _srcObjVar << " = pvs.MEDReader(FileName='" << _fileName << "');";
279   pushAndExecPyLine(oss.str()); oss.str("");
280   oss << "medcalc.SelectSourceField(" << _srcObjVar << ", '" << _meshName << "', '"
281       << _fieldName << "', '" << typ << "');";
282   pushAndExecPyLine(oss.str()); oss.str("");
283   oss << _srcObjVar << ".GenerateVectors = 1;";
284   pushAndExecPyLine(oss.str()); oss.str("");
285
286   // Deal with GAUSS fields:
287   if(_mcFieldType == MEDCoupling::ON_GAUSS_PT)
288     {
289       std::ostringstream oss, oss2;
290       oss2 << "__srcObj" << GeneratePythonId();
291       oss << oss2.str() << " = pvs.GaussPoints(Input=" << _srcObjVar << ");";
292       pushAndExecPyLine(oss.str()); oss.str("");
293       // Now the source becomes the result of the CellDatatoPointData:
294       _srcObjVar = oss2.str();
295       oss << _srcObjVar << ".SelectSourceArray = ['CELLS', 'ELGA@0'];";
296       pushAndExecPyLine(oss.str()); oss.str("");
297     }
298   if(_mcFieldType == MEDCoupling::ON_GAUSS_NE)
299     {
300       std::ostringstream oss, oss2;
301       oss2 << "__srcObj" << GeneratePythonId();
302       oss << oss2.str() << " = pvs.ELNOMesh(Input=" << _srcObjVar << ");";
303       pushAndExecPyLine(oss.str()); oss.str("");
304       // Now the source becomes the result of the CellDatatoPointData:
305       _srcObjVar = oss2.str();
306     }
307 }
308
309 void
310 MEDPresentation::setOrCreateRenderView()
311 {
312   std::ostringstream oss2;
313
314   std::string view(getRenderViewVar());
315   oss2 << "pvs._DisableFirstRenderCameraReset();";
316   pushAndExecPyLine(oss2.str()); oss2.str("");
317   if (_viewMode == MEDCALC::VIEW_MODE_OVERLAP) {
318       // this might potentially re-assign to an existing view variable, but this is OK, we
319       // normally reassign exaclty the same RenderView object.
320       oss2 << view << " = pvs.GetActiveViewOrCreate('RenderView');";
321       pushAndExecPyLine(oss2.str()); oss2.str("");
322   } else if (_viewMode == MEDCALC::VIEW_MODE_REPLACE) {
323       // same as above
324       oss2 << view << " = pvs.GetActiveViewOrCreate('RenderView');";
325       pushAndExecPyLine(oss2.str()); oss2.str("");
326       oss2 << "pvs.active_objects.source and pvs.Hide(view=" << view << ");";
327       pushAndExecPyLine(oss2.str()); oss2.str("");
328       oss2 << "pvs.Render();";
329       pushAndExecPyLine(oss2.str()); oss2.str("");
330   } else if (_viewMode == MEDCALC::VIEW_MODE_NEW_LAYOUT) {
331       oss2 <<  "__layout1 = pvs.servermanager.misc.ViewLayout(registrationGroup='layouts');";
332       pushAndExecPyLine(oss2.str()); oss2.str("");
333       oss2 << view << " = pvs.CreateView('RenderView');";
334       pushAndExecPyLine(oss2.str()); oss2.str("");
335   } else if (_viewMode == MEDCALC::VIEW_MODE_SPLIT_VIEW) {
336       oss2 << view << " = pvs.CreateView('RenderView');";
337       pushAndExecPyLine(oss2.str()); oss2.str("");
338   }
339 }
340
341 void
342 MEDPresentation::resetCameraAndRender()
343 {
344   pushAndExecPyLine(getRenderViewVar() + ".ResetCamera();");
345   pushAndExecPyLine("pvs.Render();");
346 }
347
348 void
349 MEDPresentation::selectFieldComponent()
350 {
351   std::ostringstream oss, oss_l;
352   std::string ret;
353
354   if (_selectedComponentIndex != -1)
355     {
356       oss << _lutVar << ".VectorMode = 'Component';";
357       pushAndExecPyLine(oss.str()); oss.str("");
358       oss << _lutVar << ".VectorComponent = " << _selectedComponentIndex << ";";
359       pushAndExecPyLine(oss.str()); oss.str("");
360     }
361   else  // Euclidean norm
362     {
363       oss << _lutVar << ".VectorMode = 'Magnitude';";
364       pushAndExecPyLine(oss.str()); oss.str("");
365     }
366 }
367
368 /**
369  * Needs the LUT, so to be called after selectColorMap for the first time.
370  */
371 void
372 MEDPresentation::scalarBarTitle()
373 {
374   // get selected component name:
375   std::string compoName;
376   if (_selectedComponentIndex != -1)
377     {
378       std::ostringstream oss1;
379       oss1 << MEDPresentation::PROP_COMPONENT << _selectedComponentIndex;
380       compoName = getStringProperty(oss1.str());
381     }
382   else
383     {
384       if (getIntProperty(MEDPresentation::PROP_NB_COMPONENTS) == 1)
385         compoName = "";
386       else
387         compoName = "Magnitude";
388     }
389   std::ostringstream oss;
390   oss << "pvs.GetScalarBar(" << _lutVar << ").ComponentTitle = '" << compoName << "';";
391   pushAndExecPyLine(oss.str()); oss.str("");
392 }
393
394 void
395 MEDPresentation::selectColorMap()
396 {
397   std::ostringstream oss, oss2;
398
399   oss2 << _lutVar << " = pvs.GetColorTransferFunction('" << _fieldName << "');";
400   pushAndExecPyLine(oss2.str());
401
402   switch (_colorMap) {
403   case MEDCALC::COLOR_MAP_BLUE_TO_RED_RAINBOW:
404     oss << _lutVar << ".ApplyPreset('Blue to Red Rainbow',True);";
405     break;
406   case MEDCALC::COLOR_MAP_COOL_TO_WARM:
407     oss << _lutVar << ".ApplyPreset('Cool to Warm',True);";
408     break;
409   default:
410     STDLOG("MEDPresentation::getColorMapCommand(): invalid colormap!");
411     throw KERNEL::createSalomeException("MEDPresentation::getColorMapCommand(): invalid colormap!");
412   }
413   pushAndExecPyLine(oss.str());
414
415   selectFieldComponent(); // somehow PV keeps the LUT parameters of the previous presentation, so better reset this.
416 }
417
418 void
419 MEDPresentation::showObject()
420 {
421   std::ostringstream oss;
422   oss << _dispVar << " = pvs.Show(" << _objVar << ", " << getRenderViewVar() << ");";
423   pushAndExecPyLine(oss.str());
424 }
425
426 void
427 MEDPresentation::showScalarBar()
428 {
429   std::ostringstream oss;
430   oss << _dispVar <<  ".SetScalarBarVisibility(" << getRenderViewVar() << ", True);";
431   pushAndExecPyLine(oss.str());
432 }
433
434 void
435 MEDPresentation::colorBy(const std::string & fieldType)
436 {
437   std::ostringstream oss;
438   oss << "pvs.ColorBy(" << _dispVar << ", ('" << fieldType << "', '" << _fieldName << "'));";
439   pushAndExecPyLine(oss.str());
440 }
441
442 void
443 MEDPresentation::rescaleTransferFunction()
444 {
445   std::ostringstream oss;
446   switch(_sbRange)
447   {
448     case MEDCALC::SCALAR_BAR_ALL_TIMESTEPS:
449       oss << _dispVar << ".RescaleTransferFunctionToDataRangeOverTime();";
450       break;
451     case MEDCALC::SCALAR_BAR_CURRENT_TIMESTEP:
452       oss << _dispVar << ".RescaleTransferFunctionToDataRange(False);";
453       break;
454     default:
455       STDLOG("MEDPresentation::getRescaleCommand(): invalid range!");
456       throw KERNEL::createSalomeException("MEDPresentation::getRescaleCommand(): invalid range!");
457   }
458   pushAndExecPyLine(oss.str()); oss.str("");
459   // Get min-max
460   oss << _rangeVar << " = [" << _dispVar << ".LookupTable.RGBPoints[0], " << _dispVar << ".LookupTable.RGBPoints[-4]];";
461   pushAndExecPyLine(oss.str());
462
463   // Adapt scalar bar title
464   scalarBarTitle();
465 }
466
467
468
469 int
470 MEDPresentation::GeneratePythonId()
471 {
472   static int INIT_ID = 0;
473   return INIT_ID++;
474 }
475
476 void
477 MEDPresentation::activateView()
478 {
479   MEDPyLockWrapper lock;
480   pushAndExecPyLine("pvs.SetActiveView(" + getRenderViewVar() + ");");
481 }
482
483
484 std::string
485 MEDPresentation::paravisDump() const
486 {
487   using namespace std;
488   ostringstream oss;
489   for (vector<string>::const_iterator it=_pythonCmds.begin(); it != _pythonCmds.end(); ++it)
490     {
491       oss << (*it);
492       oss << "\n";
493     }
494   return oss.str();
495 }
496
497 /**
498  * Query all available component names for the field associated with this presentation.
499  * Fills in all the corresponding string properties:
500  *  - PROP_COMPONENT1
501  *  - PROP_COMPONENT2
502  *    etc...
503  *  and the number of components.
504  */
505 void
506 MEDPresentation::fillAvailableFieldComponents()
507 {
508   MEDPyLockWrapper lock;  // GIL!
509   std::string typ;
510
511   if(_pvFieldType == "CELLS") {
512       typ = "CellData";
513   }
514   else if (_pvFieldType == "POINTS") {
515       typ = "PointData";
516   }
517   else {
518       std::string msg("Unsupported spatial discretisation: " + _pvFieldType);
519       STDLOG(msg);
520       throw KERNEL::createSalomeException(msg.c_str());
521   }
522
523   std::ostringstream oss;
524   oss << "__nbCompo = " << _srcObjVar << "." << typ << ".GetArray('" <<  _fieldName << "').GetNumberOfComponents();";
525   execPyLine(oss.str());
526   PyObject* p_obj = getPythonObjectFromMain("__nbCompo");
527   long nbCompo;
528   if (p_obj && PyInt_Check(p_obj))
529     nbCompo = PyInt_AS_LONG(p_obj);
530   else
531     {
532       STDLOG("Unexpected Python error");
533       throw KERNEL::createSalomeException("Unexpected Python error");
534     }
535   setIntProperty(MEDPresentation::PROP_NB_COMPONENTS, nbCompo);
536   for (long i = 0; i<nbCompo; i++)
537     {
538       std::ostringstream oss2;
539       oss2 << "__compo = " << _srcObjVar << "." << typ << ".GetArray('" <<  _fieldName << "').GetComponentName(" << i << ");";
540       execPyLine(oss2.str());
541       PyObject* p_obj = getPythonObjectFromMain("__compo");
542       std::string compo;
543       if (p_obj && PyString_Check(p_obj))
544         compo = std::string(PyString_AsString(p_obj));  // pointing to internal Python memory, so make a copy!!
545       else
546         {
547           STDLOG("Unexpected Python error");
548           throw KERNEL::createSalomeException("Unexpected Python error");
549         }
550       std::ostringstream oss_p;
551       oss_p << MEDPresentation::PROP_COMPONENT << i;
552       setStringProperty(oss_p.str(), compo);
553     }
554 }
555
556 /**
557  * In case where a CELLS field needs to be converted to POINT field.
558  * This updates the source object to become the result of the CellDatatoPointData filter.
559  */
560 void
561 MEDPresentation::applyCellToPointIfNeeded()
562 {
563   if (_pvFieldType == "CELLS")
564     {
565       std::ostringstream oss, oss2;
566       // Apply Cell data to point data:
567       oss2 << "__srcObj" << GeneratePythonId();
568       oss << oss2.str() << " = pvs.CellDatatoPointData(Input=" << _srcObjVar << ");";
569       pushAndExecPyLine(oss.str()); oss.str("");
570       // Now the source becomes the result of the CellDatatoPointData:
571       _srcObjVar = oss2.str();
572     }
573 }
574
575 ///**
576 // * Convert a vector field into a 3D vector field:
577 // *  - if the vector field is already 3D, nothing to do
578 // *  - if it is 2D, then add a null component
579 // *  - otherwise (tensor field, scalar field) throw
580 // */
581 //void
582 //MEDPresentation::convertTo3DVectorField()
583 //{
584 //  std::ostringstream oss, oss1, oss2, oss3;
585 //
586 //  int nbCompo = getIntProperty(MEDPresentation::PROP_NB_COMPONENTS);
587 //  if (nbCompo < 2 || nbCompo > 3)
588 //    {
589 //      oss << "The field '" << _fieldName << "' must have 2 or 3 components for this presentation!";
590 //      STDLOG(oss.str());
591 //      throw KERNEL::createSalomeException(oss.str().c_str());
592 //    }
593 //  if (nbCompo == 3)
594 //    return;
595 //
596 //  // Apply calculator:
597 //  oss2 << "__srcObj" << GeneratePythonId();
598 //  oss << oss2.str() << " = pvs.Calculator(Input=" << _srcObjVar << ");";
599 //  pushAndExecPyLine(oss.str()); oss.str("");
600 //  // Now the source becomes the result of the CellDatatoPointData:
601 //  _srcObjVar = oss2.str();
602 //  std::string typ;
603 //  if(_pvFieldType == "CELLS")
604 //    typ = "Cell Data";
605 //  else if(_pvFieldType == "POINTS")
606 //    typ = "Point Data";
607 //  else
608 //    {
609 //      oss3 << "Field '" << _fieldName << "' has invalid field type";
610 //      STDLOG(oss3.str());
611 //      throw KERNEL::createSalomeException(oss3.str().c_str());
612 //    }
613 //  oss << _srcObjVar << ".AttributeMode = '" <<  typ << "';";
614 //  pushAndExecPyLine(oss.str()); oss.str("");
615 //  oss << _srcObjVar << ".ResultArrayName = '" <<  _fieldName << "_CALC';";  // will never be needed I think
616 //  pushAndExecPyLine(oss.str()); oss.str("");
617 //  oss << _srcObjVar << ".Function = '" <<  _fieldName << "_0*iHat + " << _fieldName << "_1*jHat + 0.0*zHat';";
618 //  pushAndExecPyLine(oss.str()); oss.str("");
619 //}
620