From: vsr Date: Tue, 11 Dec 2012 12:44:24 +0000 (+0000) Subject: Merge from V6_6_BR (V6_6_0rc2) 11/12/2012 X-Git-Tag: V6_main_FINAL~466 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=edd5882117a40d95410f26b3c8ba44c40c99d0f3;p=tools%2Fmedcoupling.git Merge from V6_6_BR (V6_6_0rc2) 11/12/2012 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index a431ab0ba..16a8d9636 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ IF(COMMAND cmake_policy) ENDIF(COMMAND cmake_policy) ENABLE_TESTING() -SET(VERSION "6.5.0") +SET(VERSION "6.6.0") SET(VERSION_DEV "1") SET(WITH_MEDMEMGUI "0") diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index af1299164..10599e26c 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -23,9 +23,18 @@ include $(top_srcdir)/adm_local/unix/make_common_starter.am DOX_INPUT_FILE = Doxyfile_med_user +DOX_EXTRA_FILES = medcouplingexamples.dox + guidocdir = $(docdir)/gui/MED guidoc_DATA = images/head.png +# documentation +html-local: $(DOXY_INPUT_FILE) $(DOX_EXTRA_FILES) + @doxygen $(DOX_INPUT_FILE) + +%.dox: %.doxy + @python $(srcdir)/BuildPyExamplesFromCPP.py $< $(top_builddir)/doc/doxygen + install-data-local : html-local @if test -d doc_ref_user; then \ $(INSTALL) -d $(DESTDIR)$(docdir)/gui/MED; \ @@ -41,7 +50,7 @@ uninstall-local: rm -rf $(DESTDIR)$(docdir)/gui/MED clean-local: - rm -rf doc_ref_user log_user + rm -rf doc_ref_user log_user $(DOX_EXTRA_FILES) EXTRA_DIST += figures \ main.dox \ @@ -70,5 +79,6 @@ EXTRA_DIST += figures \ static/footer.html \ static/doxygen.css \ images \ - BuildPyExamplesFromCPP.py \ - medcouplingexamples.doxy + BuildPyExamplesFromCPP.py + +EXTRA_DIST += $(DOX_EXTRA_FILES:%.dox=%.doxy) diff --git a/src/INTERP_KERNEL/CMakeLists.txt b/src/INTERP_KERNEL/CMakeLists.txt index 8d9d2463a..02d8637bd 100644 --- a/src/INTERP_KERNEL/CMakeLists.txt +++ b/src/INTERP_KERNEL/CMakeLists.txt @@ -65,8 +65,13 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/GaussPoints ) +SET(PLATFORM_MMAP) +IF(NOT WINDOWS) + SET(PLATFORM_MMAP "-D_POSIX_MAPPED_FILES") +ENDIF(NOT WINDOWS) + ADD_LIBRARY(interpkernel SHARED ${interpkernel_SOURCES}) -SET_TARGET_PROPERTIES(interpkernel PROPERTIES COMPILE_FLAGS "${PLATFORM_DEFINITIONS}") +SET_TARGET_PROPERTIES(interpkernel PROPERTIES COMPILE_FLAGS "${PLATFORM_DEFINITIONS} ${PLATFORM_MMAP}") TARGET_LINK_LIBRARIES(interpkernel ${PLATFORM_LIBS}) INSTALL(TARGETS interpkernel DESTINATION ${MED_salomelib_LIBS}) diff --git a/src/INTERP_KERNEL/ExprEval/InterpKernelExprParser.cxx b/src/INTERP_KERNEL/ExprEval/InterpKernelExprParser.cxx index e75a2e5f4..a8d02a3b5 100644 --- a/src/INTERP_KERNEL/ExprEval/InterpKernelExprParser.cxx +++ b/src/INTERP_KERNEL/ExprEval/InterpKernelExprParser.cxx @@ -1009,7 +1009,7 @@ void ExprParser::compileX86_64LowLev(std::vector& ass) const void LeafExprVal::compileX86(std::vector& ass) const { ass.push_back("sub esp,8"); - int *b=(int *)&_value,*c=(int *)&_value; + const int *b=reinterpret_cast(&_value),*c=reinterpret_cast(&_value); c++; std::ostringstream oss; oss << std::hex; @@ -1025,7 +1025,7 @@ void LeafExprVal::compileX86(std::vector& ass) const void LeafExprVal::compileX86_64(std::vector& ass) const { ass.push_back("sub rsp,8"); - int *b=(int *)&_value,*c=(int *)&_value; + const int *b=reinterpret_cast(&_value),*c=reinterpret_cast(&_value); c++; std::ostringstream oss; oss << std::hex; diff --git a/src/INTERP_KERNEL/ExprEval/InterpKernelFunction.cxx b/src/INTERP_KERNEL/ExprEval/InterpKernelFunction.cxx index c8e4d5b8d..6e4f13e7b 100644 --- a/src/INTERP_KERNEL/ExprEval/InterpKernelFunction.cxx +++ b/src/INTERP_KERNEL/ExprEval/InterpKernelFunction.cxx @@ -37,6 +37,18 @@ const char SinFunction::REPR[]="sin"; const char TanFunction::REPR[]="tan"; +const char ACosFunction::REPR[]="acos"; + +const char ASinFunction::REPR[]="asin"; + +const char ATanFunction::REPR[]="atan"; + +const char CoshFunction::REPR[]="cosh"; + +const char SinhFunction::REPR[]="sinh"; + +const char TanhFunction::REPR[]="tanh"; + const char SqrtFunction::REPR[]="sqrt"; const char AbsFunction::REPR[]="abs"; @@ -95,6 +107,18 @@ Function *FunctionsFactory::buildUnaryFuncFromString(const char *type) throw(INT return new SinFunction; if(tmp==TanFunction::REPR) return new TanFunction; + if(tmp==ACosFunction::REPR) + return new ACosFunction; + if(tmp==ASinFunction::REPR) + return new ASinFunction; + if(tmp==ATanFunction::REPR) + return new ATanFunction; + if(tmp==CoshFunction::REPR) + return new CoshFunction; + if(tmp==SinhFunction::REPR) + return new SinhFunction; + if(tmp==TanhFunction::REPR) + return new TanhFunction; if(tmp==SqrtFunction::REPR) return new SqrtFunction; if(tmp==AbsFunction::REPR) @@ -312,6 +336,156 @@ bool TanFunction::isACall() const return true; } +ACosFunction::~ACosFunction() +{ +} + +void ACosFunction::operate(std::vector& stack) const throw(INTERP_KERNEL::Exception) +{ + Value *val=stack.back(); + val->acos(); +} + +void ACosFunction::operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception) +{ + throw INTERP_KERNEL::Exception("Assembly Not implemented yet !"); +} + +const char *ACosFunction::getRepr() const +{ + return REPR; +} + +bool ACosFunction::isACall() const +{ + return true; +} + +ASinFunction::~ASinFunction() +{ +} + +void ASinFunction::operate(std::vector& stack) const throw(INTERP_KERNEL::Exception) +{ + Value *val=stack.back(); + val->asin(); +} + +void ASinFunction::operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception) +{ + throw INTERP_KERNEL::Exception("Assembly Not implemented yet !"); +} + +const char *ASinFunction::getRepr() const +{ + return REPR; +} + +bool ASinFunction::isACall() const +{ + return true; +} + +ATanFunction::~ATanFunction() +{ +} + +void ATanFunction::operate(std::vector& stack) const throw(INTERP_KERNEL::Exception) +{ + Value *val=stack.back(); + val->atan(); +} + +void ATanFunction::operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception) +{ + throw INTERP_KERNEL::Exception("Assembly Not implemented yet !"); +} + +const char *ATanFunction::getRepr() const +{ + return REPR; +} + +bool ATanFunction::isACall() const +{ + return true; +} + +CoshFunction::~CoshFunction() +{ +} + +void CoshFunction::operate(std::vector& stack) const throw(INTERP_KERNEL::Exception) +{ + Value *val=stack.back(); + val->cosh(); +} + +void CoshFunction::operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception) +{ + throw INTERP_KERNEL::Exception("Assembly Not implemented yet !"); +} + +const char *CoshFunction::getRepr() const +{ + return REPR; +} + +bool CoshFunction::isACall() const +{ + return true; +} + +SinhFunction::~SinhFunction() +{ +} + +void SinhFunction::operate(std::vector& stack) const throw(INTERP_KERNEL::Exception) +{ + Value *val=stack.back(); + val->sinh(); +} + +void SinhFunction::operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception) +{ + throw INTERP_KERNEL::Exception("Assembly Not implemented yet !"); +} + +const char *SinhFunction::getRepr() const +{ + return REPR; +} + +bool SinhFunction::isACall() const +{ + return true; +} + +TanhFunction::~TanhFunction() +{ +} + +void TanhFunction::operate(std::vector& stack) const throw(INTERP_KERNEL::Exception) +{ + Value *val=stack.back(); + val->tanh(); +} + +void TanhFunction::operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception) +{ + throw INTERP_KERNEL::Exception("Assembly Not implemented yet !"); +} + +const char *TanhFunction::getRepr() const +{ + return REPR; +} + +bool TanhFunction::isACall() const +{ + return true; +} + SqrtFunction::~SqrtFunction() { } diff --git a/src/INTERP_KERNEL/ExprEval/InterpKernelFunction.hxx b/src/INTERP_KERNEL/ExprEval/InterpKernelFunction.hxx index f49c75943..b63382683 100644 --- a/src/INTERP_KERNEL/ExprEval/InterpKernelFunction.hxx +++ b/src/INTERP_KERNEL/ExprEval/InterpKernelFunction.hxx @@ -131,6 +131,78 @@ namespace INTERP_KERNEL static const char REPR[]; }; + class INTERPKERNEL_EXPORT ACosFunction : public UnaryFunction + { + public: + ~ACosFunction(); + void operate(std::vector& stack) const throw(INTERP_KERNEL::Exception); + void operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception); + const char *getRepr() const; + bool isACall() const; + public: + static const char REPR[]; + }; + + class INTERPKERNEL_EXPORT ASinFunction : public UnaryFunction + { + public: + ~ASinFunction(); + void operate(std::vector& stack) const throw(INTERP_KERNEL::Exception); + void operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception); + const char *getRepr() const; + bool isACall() const; + public: + static const char REPR[]; + }; + + class INTERPKERNEL_EXPORT ATanFunction : public UnaryFunction + { + public: + ~ATanFunction(); + void operate(std::vector& stack) const throw(INTERP_KERNEL::Exception); + void operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception); + const char *getRepr() const; + bool isACall() const; + public: + static const char REPR[]; + }; + + class INTERPKERNEL_EXPORT CoshFunction : public UnaryFunction + { + public: + ~CoshFunction(); + void operate(std::vector& stack) const throw(INTERP_KERNEL::Exception); + void operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception); + const char *getRepr() const; + bool isACall() const; + public: + static const char REPR[]; + }; + + class INTERPKERNEL_EXPORT SinhFunction : public UnaryFunction + { + public: + ~SinhFunction(); + void operate(std::vector& stack) const throw(INTERP_KERNEL::Exception); + void operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception); + const char *getRepr() const; + bool isACall() const; + public: + static const char REPR[]; + }; + + class INTERPKERNEL_EXPORT TanhFunction : public UnaryFunction + { + public: + ~TanhFunction(); + void operate(std::vector& stack) const throw(INTERP_KERNEL::Exception); + void operateX86(std::vector& asmb) const throw(INTERP_KERNEL::Exception); + const char *getRepr() const; + bool isACall() const; + public: + static const char REPR[]; + }; + class INTERPKERNEL_EXPORT SqrtFunction : public UnaryFunction { public: diff --git a/src/INTERP_KERNEL/ExprEval/InterpKernelValue.cxx b/src/INTERP_KERNEL/ExprEval/InterpKernelValue.cxx index 6564cfd25..3a24ef6da 100644 --- a/src/INTERP_KERNEL/ExprEval/InterpKernelValue.cxx +++ b/src/INTERP_KERNEL/ExprEval/InterpKernelValue.cxx @@ -80,6 +80,36 @@ void ValueDouble::tan() throw(INTERP_KERNEL::Exception) _data=std::tan(_data); } +void ValueDouble::acos() throw(INTERP_KERNEL::Exception) +{ + _data=std::acos(_data); +} + +void ValueDouble::asin() throw(INTERP_KERNEL::Exception) +{ + _data=std::asin(_data); +} + +void ValueDouble::atan() throw(INTERP_KERNEL::Exception) +{ + _data=std::atan(_data); +} + +void ValueDouble::cosh() throw(INTERP_KERNEL::Exception) +{ + _data=std::cosh(_data); +} + +void ValueDouble::sinh() throw(INTERP_KERNEL::Exception) +{ + _data=std::sinh(_data); +} + +void ValueDouble::tanh() throw(INTERP_KERNEL::Exception) +{ + _data=std::tanh(_data); +} + void ValueDouble::abs() throw(INTERP_KERNEL::Exception) { if(_data<0.) @@ -229,6 +259,36 @@ void ValueUnit::tan() throw(INTERP_KERNEL::Exception) unsupportedOp(TanFunction::REPR); } +void ValueUnit::acos() throw(INTERP_KERNEL::Exception) +{ + unsupportedOp(ACosFunction::REPR); +} + +void ValueUnit::asin() throw(INTERP_KERNEL::Exception) +{ + unsupportedOp(ASinFunction::REPR); +} + +void ValueUnit::atan() throw(INTERP_KERNEL::Exception) +{ + unsupportedOp(ATanFunction::REPR); +} + +void ValueUnit::cosh() throw(INTERP_KERNEL::Exception) +{ + unsupportedOp(CoshFunction::REPR); +} + +void ValueUnit::sinh() throw(INTERP_KERNEL::Exception) +{ + unsupportedOp(SinhFunction::REPR); +} + +void ValueUnit::tanh() throw(INTERP_KERNEL::Exception) +{ + unsupportedOp(TanhFunction::REPR); +} + void ValueUnit::abs() throw(INTERP_KERNEL::Exception) { unsupportedOp(AbsFunction::REPR); @@ -395,6 +455,48 @@ void ValueDoubleExpr::tan() throw(INTERP_KERNEL::Exception) std::transform(_dest_data,_dest_data+_sz_dest_data,_dest_data,std::ptr_fun(std::tan)); } +void ValueDoubleExpr::acos() throw(INTERP_KERNEL::Exception) +{ + double *it=std::find_if(_dest_data,_dest_data+_sz_dest_data,std::bind2nd(std::less(),-1.)); + if(it!=_dest_data+_sz_dest_data) + throw INTERP_KERNEL::Exception("Trying to apply acos on < 1. value !"); + it=std::find_if(_dest_data,_dest_data+_sz_dest_data,std::bind2nd(std::greater(),1.)); + if(it!=_dest_data+_sz_dest_data) + throw INTERP_KERNEL::Exception("Trying to apply acos on > 1. value !"); + std::transform(_dest_data,_dest_data+_sz_dest_data,_dest_data,std::ptr_fun(std::acos)); +} + +void ValueDoubleExpr::asin() throw(INTERP_KERNEL::Exception) +{ + double *it=std::find_if(_dest_data,_dest_data+_sz_dest_data,std::bind2nd(std::less(),-1.)); + if(it!=_dest_data+_sz_dest_data) + throw INTERP_KERNEL::Exception("Trying to apply asin on < 1. value !"); + it=std::find_if(_dest_data,_dest_data+_sz_dest_data,std::bind2nd(std::greater(),1.)); + if(it!=_dest_data+_sz_dest_data) + throw INTERP_KERNEL::Exception("Trying to apply asin on > 1. value !"); + std::transform(_dest_data,_dest_data+_sz_dest_data,_dest_data,std::ptr_fun(std::asin)); +} + +void ValueDoubleExpr::atan() throw(INTERP_KERNEL::Exception) +{ + std::transform(_dest_data,_dest_data+_sz_dest_data,_dest_data,std::ptr_fun(std::atan)); +} + +void ValueDoubleExpr::cosh() throw(INTERP_KERNEL::Exception) +{ + std::transform(_dest_data,_dest_data+_sz_dest_data,_dest_data,std::ptr_fun(std::cosh)); +} + +void ValueDoubleExpr::sinh() throw(INTERP_KERNEL::Exception) +{ + std::transform(_dest_data,_dest_data+_sz_dest_data,_dest_data,std::ptr_fun(std::sinh)); +} + +void ValueDoubleExpr::tanh() throw(INTERP_KERNEL::Exception) +{ + std::transform(_dest_data,_dest_data+_sz_dest_data,_dest_data,std::ptr_fun(std::tanh)); +} + void ValueDoubleExpr::abs() throw(INTERP_KERNEL::Exception) { std::transform(_dest_data,_dest_data+_sz_dest_data,_dest_data,std::ptr_fun(fabs)); diff --git a/src/INTERP_KERNEL/ExprEval/InterpKernelValue.hxx b/src/INTERP_KERNEL/ExprEval/InterpKernelValue.hxx index 71d5bf0f0..36c484b04 100644 --- a/src/INTERP_KERNEL/ExprEval/InterpKernelValue.hxx +++ b/src/INTERP_KERNEL/ExprEval/InterpKernelValue.hxx @@ -41,6 +41,12 @@ namespace INTERP_KERNEL virtual void cos() throw(INTERP_KERNEL::Exception) = 0; virtual void sin() throw(INTERP_KERNEL::Exception) = 0; virtual void tan() throw(INTERP_KERNEL::Exception) = 0; + virtual void acos() throw(INTERP_KERNEL::Exception) = 0; + virtual void asin() throw(INTERP_KERNEL::Exception) = 0; + virtual void atan() throw(INTERP_KERNEL::Exception) = 0; + virtual void cosh() throw(INTERP_KERNEL::Exception) = 0; + virtual void sinh() throw(INTERP_KERNEL::Exception) = 0; + virtual void tanh() throw(INTERP_KERNEL::Exception) = 0; virtual void abs() throw(INTERP_KERNEL::Exception) = 0; virtual void exp() throw(INTERP_KERNEL::Exception) = 0; virtual void ln() throw(INTERP_KERNEL::Exception) = 0; @@ -74,6 +80,12 @@ namespace INTERP_KERNEL void cos() throw(INTERP_KERNEL::Exception); void sin() throw(INTERP_KERNEL::Exception); void tan() throw(INTERP_KERNEL::Exception); + void acos() throw(INTERP_KERNEL::Exception); + void asin() throw(INTERP_KERNEL::Exception); + void atan() throw(INTERP_KERNEL::Exception); + void cosh() throw(INTERP_KERNEL::Exception); + void sinh() throw(INTERP_KERNEL::Exception); + void tanh() throw(INTERP_KERNEL::Exception); void abs() throw(INTERP_KERNEL::Exception); void exp() throw(INTERP_KERNEL::Exception); void ln() throw(INTERP_KERNEL::Exception); @@ -112,6 +124,12 @@ namespace INTERP_KERNEL void cos() throw(INTERP_KERNEL::Exception); void sin() throw(INTERP_KERNEL::Exception); void tan() throw(INTERP_KERNEL::Exception); + void acos() throw(INTERP_KERNEL::Exception); + void asin() throw(INTERP_KERNEL::Exception); + void atan() throw(INTERP_KERNEL::Exception); + void cosh() throw(INTERP_KERNEL::Exception); + void sinh() throw(INTERP_KERNEL::Exception); + void tanh() throw(INTERP_KERNEL::Exception); void abs() throw(INTERP_KERNEL::Exception); void exp() throw(INTERP_KERNEL::Exception); void ln() throw(INTERP_KERNEL::Exception); @@ -152,6 +170,12 @@ namespace INTERP_KERNEL void cos() throw(INTERP_KERNEL::Exception); void sin() throw(INTERP_KERNEL::Exception); void tan() throw(INTERP_KERNEL::Exception); + void acos() throw(INTERP_KERNEL::Exception); + void asin() throw(INTERP_KERNEL::Exception); + void atan() throw(INTERP_KERNEL::Exception); + void cosh() throw(INTERP_KERNEL::Exception); + void sinh() throw(INTERP_KERNEL::Exception); + void tanh() throw(INTERP_KERNEL::Exception); void abs() throw(INTERP_KERNEL::Exception); void exp() throw(INTERP_KERNEL::Exception); void ln() throw(INTERP_KERNEL::Exception); diff --git a/src/INTERP_KERNEL/GaussPoints/InterpKernelGaussCoords.cxx b/src/INTERP_KERNEL/GaussPoints/InterpKernelGaussCoords.cxx index 57e9c936a..0fa9d7b5a 100644 --- a/src/INTERP_KERNEL/GaussPoints/InterpKernelGaussCoords.cxx +++ b/src/INTERP_KERNEL/GaussPoints/InterpKernelGaussCoords.cxx @@ -359,7 +359,7 @@ void GaussInfo::initLocalInfo() throw (INTERP_KERNEL::Exception) if(!aSatify) { - hexa8aInit(); + hexa8bInit(); aSatify = isSatisfy(); CHECK_MACRO; } @@ -373,7 +373,7 @@ void GaussInfo::initLocalInfo() throw (INTERP_KERNEL::Exception) if(!aSatify) { - hexa20aInit(); + hexa20bInit(); aSatify = isSatisfy(); CHECK_MACRO; } diff --git a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DComposedEdge.cxx b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DComposedEdge.cxx index cdf2ca336..960ce5183 100644 --- a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DComposedEdge.cxx +++ b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DComposedEdge.cxx @@ -136,6 +136,21 @@ void ComposedEdge::initLocations() const (*iter)->initLocations(); } +void ComposedEdge::initLocationsWithOther(const ComposedEdge& other) const +{ + std::set s1,s2; + for(std::list::const_iterator it1=_sub_edges.begin();it1!=_sub_edges.end();it1++) + s1.insert((*it1)->getPtr()); + for(std::list::const_iterator it2=other._sub_edges.begin();it2!=other._sub_edges.end();it2++) + s2.insert((*it2)->getPtr()); + initLocations(); + other.initLocations(); + std::vector s3; + std::set_intersection(s1.begin(),s1.end(),s2.begin(),s2.end(),std::back_insert_iterator< std::vector >(s3)); + for(std::vector::const_iterator it3=s3.begin();it3!=s3.end();it3++) + (*it3)->declareOn(); +} + ComposedEdge *ComposedEdge::clone() const { return new ComposedEdge(*this); diff --git a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DComposedEdge.hxx b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DComposedEdge.hxx index 8fbf7bd2e..e3bf49f18 100644 --- a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DComposedEdge.hxx +++ b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DComposedEdge.hxx @@ -50,6 +50,7 @@ namespace INTERP_KERNEL bool presenceOfOn() const; bool presenceOfQuadraticEdge() const; void initLocations() const; + void initLocationsWithOther(const ComposedEdge& other) const; ComposedEdge *clone() const; bool isNodeIn(Node *n) const; double getArea() const; diff --git a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DQuadraticPolygon.cxx b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DQuadraticPolygon.cxx index 69b6dacad..b0ee4f1c2 100644 --- a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DQuadraticPolygon.cxx +++ b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DQuadraticPolygon.cxx @@ -392,13 +392,37 @@ void QuadraticPolygon::appendSubEdgeFromCrudeDataArray(Edge *baseEdge, std::size */ void QuadraticPolygon::buildFromCrudeDataArray2(const std::map& mapp, bool isQuad, const int *nodalBg, const double *coords, const int *descBg, const int *descEnd, const std::vector >& intersectEdges, const INTERP_KERNEL::QuadraticPolygon& pol1, const int *descBg1, const int *descEnd1, const std::vector >& intersectEdges1, - const std::vector< std::vector >& colinear1) + const std::vector< std::vector >& colinear1, + std::map >& alreadyExistingIn2) { std::size_t nbOfSeg=std::distance(descBg,descEnd); for(std::size_t i=0;i0; int edgeId=abs(descBg[i])-1;//current edge id of pol2 + std::map >::const_iterator it1=alreadyExistingIn2.find(descBg[i]),it2=alreadyExistingIn2.find(-descBg[i]); + if(it1!=alreadyExistingIn2.end() || it2!=alreadyExistingIn2.end()) + { + bool sameDir=(it1!=alreadyExistingIn2.end()); + const std::vector& edgesAlreadyBuilt=sameDir?(*it1).second:(*it2).second; + if(sameDir) + { + for(std::vector::const_iterator it3=edgesAlreadyBuilt.begin();it3!=edgesAlreadyBuilt.end();it3++) + { + Edge *ee=(*it3)->getPtr(); ee->incrRef(); + pushBack(new ElementaryEdge(ee,(*it3)->getDirection())); + } + } + else + { + for(std::vector::const_reverse_iterator it4=edgesAlreadyBuilt.rbegin();it4!=edgesAlreadyBuilt.rend();it4++) + { + Edge *ee=(*it4)->getPtr(); ee->incrRef(); + pushBack(new ElementaryEdge(ee,!(*it4)->getDirection())); + } + } + continue; + } bool directos=colinear1[edgeId].empty(); std::vector > > idIns1; int offset1=0; @@ -420,7 +444,14 @@ void QuadraticPolygon::buildFromCrudeDataArray2(const std::map::const_reverse_iterator it5=_sub_edges.rbegin(); + for(std::size_t p=0;p reuse Edge instance of pol1 ElementaryEdge *e=pol1[offset1+(direct1?offset2:nbOfSubEdges1-offset2-1)]; Edge *ee=e->getPtr(); ee->incrRef(); - pushBack(new ElementaryEdge(ee,!(direct1^direction11))); + ElementaryEdge *e2=new ElementaryEdge(ee,!(direct1^direction11)); + pushBack(e2); + alreadyExistingIn2[descBg[i]].push_back(e2); } } } @@ -505,9 +539,9 @@ void QuadraticPolygon::updateLocOfEdgeFromCrudeDataArray2(const int *descBg, con std::size_t nbOfSubEdges1=subEdge1PossiblyAlreadyIn1.size()/2; int offset2=0; bool found=false; - for(std::size_t k=0;k res=buildIntersectionPolygons(other,*this); for(std::vector::iterator it=res.begin();it!=res.end();it++) { @@ -863,6 +897,16 @@ void QuadraticPolygon::performLocatingOperation(QuadraticPolygon& pol2) const } } +void QuadraticPolygon::performLocatingOperationSlow(QuadraticPolygon& pol2) const +{ + IteratorOnComposedEdge it(&pol2); + for(it.first();!it.finished();it.next()) + { + ElementaryEdge *cur=it.current(); + cur->locateFullyMySelfAbsolute(*this); + } +} + /*! * Given 2 polygons 'pol1' and 'pol2' (localized) the resulting polygons are returned. * @@ -896,7 +940,7 @@ std::vector QuadraticPolygon::buildIntersectionPolygons(cons std::list QuadraticPolygon::zipConsecutiveInSegments() const { std::list ret; - IteratorOnComposedEdge it((ComposedEdge *)this); + IteratorOnComposedEdge it(const_cast(this)); int nbOfTurns=recursiveSize(); int i=0; if(!it.goToNextInOn(false,i,nbOfTurns)) @@ -1058,41 +1102,120 @@ std::list::iterator QuadraticPolygon::CheckInList(Node *n, s return iEnd; } -void QuadraticPolygon::ComputeResidual(const std::set& notUsedInPol1, const std::set& edgesInPol2OnBoundary, int idThis, - std::vector& addCoordsQuadratic, std::vector& conn, std::vector& connI, std::vector& nb1) +void QuadraticPolygon::ComputeResidual(const QuadraticPolygon& pol1, const std::set& notUsedInPol1, const std::set& edgesInPol2OnBoundary, const std::map& mapp, int offset, int idThis, + std::vector& addCoordsQuadratic, std::vector& conn, std::vector& connI, std::vector& nb1, std::vector& nb2) { - for(std::set::const_iterator it=edgesInPol2OnBoundary.begin();it!=edgesInPol2OnBoundary.end();it++) - { (*it)->initLocs(); (*it)->declareIn(); } + pol1.initLocations(); for(std::set::const_iterator it=notUsedInPol1.begin();it!=notUsedInPol1.end();it++) { (*it)->initLocs(); (*it)->declareOn(); } - std::list pol2Zip; - std::list edgesInPol2OnBoundaryL(edgesInPol2OnBoundary.begin(),edgesInPol2OnBoundary.end()); - while(!edgesInPol2OnBoundaryL.empty()) + for(std::set::const_iterator it=edgesInPol2OnBoundary.begin();it!=edgesInPol2OnBoundary.end();it++) + { (*it)->initLocs(); (*it)->declareIn(); } + //// + std::set notUsedInPol1L(notUsedInPol1); + IteratorOnComposedEdge it(const_cast(&pol1)); + int sz=pol1.size(); + std::list pol1Zip; + if(pol1.size()==(int)notUsedInPol1.size() && edgesInPol2OnBoundary.empty()) + { + pol1.appendCrudeData(mapp,0.,0.,1.,offset,addCoordsQuadratic,conn,connI); nb1.push_back(idThis); nb2.push_back(-1); + return ; + } + while(!notUsedInPol1L.empty()) { + for(int i=0;igetStartNode()->getLoc()!=IN_1 || it.current()->getLoc()!=FULL_ON_1);i++) + it.nextLoop(); + if(it.current()->getStartNode()->getLoc()!=IN_1 || it.current()->getLoc()!=FULL_ON_1) + throw INTERP_KERNEL::Exception("Presence of a target polygon fully included in source polygon ! The partition of this leads to a non simply connex cell (with hole) ! Impossible ! Such resulting cell cannot be stored in MED cell format !"); QuadraticPolygon *tmp1=new QuadraticPolygon; - Node *curN=0; - for(std::list::iterator it=edgesInPol2OnBoundaryL.begin();it!=edgesInPol2OnBoundaryL.end();it++) + do { - if((*it)->getStartNode()->getLoc()==ON_1) - { curN=(*it)->getEndNode(); edgesInPol2OnBoundaryL.erase(it); tmp1->pushBack(new ElementaryEdge(*it,true)); break; } - if((*it)->getEndNode()->getLoc()==ON_1) - { curN=(*it)->getStartNode(); edgesInPol2OnBoundaryL.erase(it); tmp1->pushBack(new ElementaryEdge(*it,false)); break; } + Edge *ee=it.current()->getPtr(); + if(ee->getLoc()==FULL_ON_1) + { + ee->incrRef(); notUsedInPol1L.erase(ee); + tmp1->pushBack(new ElementaryEdge(ee,it.current()->getDirection())); + } + it.nextLoop(); } - // - while(curN->getLoc()!=ON_1 && !edgesInPol2OnBoundaryL.empty()) + while(it.current()->getStartNode()->getLoc()!=IN_1 && !notUsedInPol1L.empty()); + pol1Zip.push_back(tmp1); + } + //// + std::list retPolsUnderContruction; + std::list edgesInPol2OnBoundaryL(edgesInPol2OnBoundary.begin(),edgesInPol2OnBoundary.end()); + std::map > pol1ZipConsumed; + while(!pol1Zip.empty() || !edgesInPol2OnBoundaryL.empty()) + { + for(std::list::iterator it1=retPolsUnderContruction.begin();it1!=retPolsUnderContruction.end();) { - for(std::list::iterator it=edgesInPol2OnBoundaryL.begin();it!=edgesInPol2OnBoundaryL.end();it++) + if((*it1)->getStartNode()==(*it1)->getEndNode()) + { + it1++; + continue; + } + Node *curN=(*it1)->getEndNode(); + bool smthHappened=false; + for(std::list::iterator it2=edgesInPol2OnBoundaryL.begin();it2!=edgesInPol2OnBoundaryL.end();) { - if((*it)->getStartNode()==curN) - { curN=(*it)->getEndNode(); edgesInPol2OnBoundaryL.erase(it); tmp1->pushBack(new ElementaryEdge(*it,true)); break; } - if((*it)->getEndNode()==curN) - { curN=(*it)->getStartNode(); edgesInPol2OnBoundaryL.erase(it); tmp1->pushBack(new ElementaryEdge(*it,false)); break; } + if(curN==(*it2)->getStartNode()) + { (*it2)->incrRef(); (*it1)->pushBack(new ElementaryEdge(*it2,true)); curN=(*it2)->getEndNode(); smthHappened=true; it2=edgesInPol2OnBoundaryL.erase(it2); } + else if(curN==(*it2)->getEndNode()) + { (*it2)->incrRef(); (*it1)->pushBack(new ElementaryEdge(*it2,false)); curN=(*it2)->getStartNode(); smthHappened=true; it2=edgesInPol2OnBoundaryL.erase(it2); } + else + it2++; } + if(smthHappened) + { + for(std::list::iterator it3=pol1Zip.begin();it3!=pol1Zip.end();) + { + if(curN==(*it3)->getStartNode()) + { + for(std::list::const_iterator it4=(*it3)->_sub_edges.begin();it4!=(*it3)->_sub_edges.end();it4++) + { (*it4)->getPtr()->incrRef(); bool dir=(*it4)->getDirection(); (*it1)->pushBack(new ElementaryEdge((*it4)->getPtr(),dir)); } + smthHappened=true; + pol1ZipConsumed[*it1].push_back(*it3); + curN=(*it3)->getEndNode(); + it3=pol1Zip.erase(it3); + } + else + it3++; + } + } + if(!smthHappened) + { + for(std::list::const_iterator it5=(*it1)->_sub_edges.begin();it5!=(*it1)->_sub_edges.end();it5++) + { + Edge *ee=(*it5)->getPtr(); + if(edgesInPol2OnBoundary.find(ee)!=edgesInPol2OnBoundary.end()) + edgesInPol2OnBoundaryL.push_back(ee); + } + for(std::list::iterator it6=pol1ZipConsumed[*it1].begin();it6!=pol1ZipConsumed[*it1].end();it6++) + pol1Zip.push_front(*it6); + pol1ZipConsumed.erase(*it1); + delete *it1; + it1=retPolsUnderContruction.erase(it1); + } + } + if(!pol1Zip.empty()) + { + QuadraticPolygon *tmp=new QuadraticPolygon; + QuadraticPolygon *first=*(pol1Zip.begin()); + for(std::list::const_iterator it4=first->_sub_edges.begin();it4!=first->_sub_edges.end();it4++) + { (*it4)->getPtr()->incrRef(); bool dir=(*it4)->getDirection(); tmp->pushBack(new ElementaryEdge((*it4)->getPtr(),dir)); } + pol1ZipConsumed[tmp].push_back(first); + retPolsUnderContruction.push_back(tmp); + pol1Zip.erase(pol1Zip.begin()); + } + } + for(std::list::iterator it1=retPolsUnderContruction.begin();it1!=retPolsUnderContruction.end();it1++) + { + if((*it1)->getStartNode()==(*it1)->getEndNode()) + { + (*it1)->appendCrudeData(mapp,0.,0.,1.,offset,addCoordsQuadratic,conn,connI); nb1.push_back(idThis); nb2.push_back(-1); + for(std::list::iterator it6=pol1ZipConsumed[*it1].begin();it6!=pol1ZipConsumed[*it1].end();it6++) + delete *it6; + delete *it1; + it1=retPolsUnderContruction.erase(it1); } - pol2Zip.push_back(tmp1); } - //pol2.zipConsecutiveInSegments(); - //std::vector ret; - //if(!pol2Zip.empty()) - // closePolygons(pol2Zip,pol1,ret); } diff --git a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DQuadraticPolygon.hxx b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DQuadraticPolygon.hxx index 2c9edcd34..9f154aa22 100644 --- a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DQuadraticPolygon.hxx +++ b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DQuadraticPolygon.hxx @@ -62,7 +62,8 @@ namespace INTERP_KERNEL const int *descBg, const int *descEnd, const std::vector >& intersectEdges); void buildFromCrudeDataArray2(const std::map& mapp, bool isQuad, const int *nodalBg, const double *coords, const int *descBg, const int *descEnd, const std::vector >& intersectEdges, const INTERP_KERNEL::QuadraticPolygon& pol1, const int *descBg1, const int *descEnd1, const std::vector >& intersectEdges1, - const std::vector< std::vector >& colinear1); + const std::vector< std::vector >& colinear1, + std::map >& alreadyExistingIn2); void updateLocOfEdgeFromCrudeDataArray2(const int *descBg, const int *descEnd, const std::vector >& intersectEdges, const INTERP_KERNEL::QuadraticPolygon& pol1, const int *descBg1, const int *descEnd1, const std::vector >& intersectEdges1, const std::vector< std::vector >& colinear1) const; void appendEdgeFromCrudeDataArray(std::size_t edgeId, const std::map& mapp, bool isQuad, const int *nodalBg, const double *coords, const int *descBg, const int *descEnd, const std::vector >& intersectEdges); @@ -79,11 +80,12 @@ namespace INTERP_KERNEL void intersectForPoint(const QuadraticPolygon& other, std::vector< int >& numberOfCreatedPointsPerEdge) const; public://Only public for tests reasons void performLocatingOperation(QuadraticPolygon& pol2) const; + void performLocatingOperationSlow(QuadraticPolygon& pol2) const; static void SplitPolygonsEachOther(QuadraticPolygon& pol1, QuadraticPolygon& pol2, int& nbOfSplits); std::vector buildIntersectionPolygons(const QuadraticPolygon& pol1, const QuadraticPolygon& pol2) const; bool amIAChanceToBeCompletedBy(const QuadraticPolygon& pol1Splitted, const QuadraticPolygon& pol2NotSplitted, bool& direction); - static void ComputeResidual(const std::set& notUsedInPol1, const std::set& edgesInPol2OnBoundary, int idThis, - std::vector& addCoordsQuadratic, std::vector& conn, std::vector& connI, std::vector& nb1); + static void ComputeResidual(const QuadraticPolygon& pol1, const std::set& notUsedInPol1, const std::set& edgesInPol2OnBoundary, const std::map& mapp, int offset, int idThis, + std::vector& addCoordsQuadratic, std::vector& conn, std::vector& connI, std::vector& nb1, std::vector& nb2); protected: std::list zipConsecutiveInSegments() const; void dumpInXfigFile(std::ostream& stream, int resolution, const Bounds& box) const; diff --git a/src/INTERP_KERNEL/Interpolation3D2D.txx b/src/INTERP_KERNEL/Interpolation3D2D.txx index b971d8978..b780a5606 100644 --- a/src/INTERP_KERNEL/Interpolation3D2D.txx +++ b/src/INTERP_KERNEL/Interpolation3D2D.txx @@ -92,15 +92,18 @@ namespace INTERP_KERNEL switch(InterpolationOptions::getIntersectionType()) { case Triangulation: - intersector=new Polyhedron3D2DIntersectorP0P0(targetMesh, - srcMesh, - dimCaracteristic, - getPrecision(), - intersectFaces, - getSplittingPolicy()); + intersector=new Polyhedron3D2DIntersectorP0P0(targetMesh, + srcMesh, + dimCaracteristic, + getPrecision(), + intersectFaces, + getSplittingPolicy()); + break; + case PointLocator: + intersector=new PointLocator3DIntersectorP0P0(targetMesh,srcMesh,getPrecision()); break; default: - throw INTERP_KERNEL::Exception("Invalid 3D intersection type for P0P0 interp specified : must be Triangulation."); + throw INTERP_KERNEL::Exception("Invalid 3D to 2D intersection type for P0P0 interp specified : must be Triangulation or PointLocator."); } } else diff --git a/src/INTERP_KERNEL/InterpolationCC.hxx b/src/INTERP_KERNEL/InterpolationCC.hxx index 88bbc00a1..e3c409592 100644 --- a/src/INTERP_KERNEL/InterpolationCC.hxx +++ b/src/INTERP_KERNEL/InterpolationCC.hxx @@ -39,7 +39,7 @@ namespace INTERP_KERNEL // static const NumberingPolicy numPol=MyMeshType::My_numPol; public: InterpolationCC(); - //InterpolationCC(const InterpolationOptions& io); + InterpolationCC(const InterpolationOptions& io); template int interpolateMeshes(const MyMeshType& srcMesh, const MyMeshType& targetMesh, MatrixType& result, const char *method); diff --git a/src/INTERP_KERNEL/InterpolationCC.txx b/src/INTERP_KERNEL/InterpolationCC.txx index da4ec44f1..84a925986 100644 --- a/src/INTERP_KERNEL/InterpolationCC.txx +++ b/src/INTERP_KERNEL/InterpolationCC.txx @@ -40,6 +40,10 @@ namespace INTERP_KERNEL { } + InterpolationCC::InterpolationCC(const InterpolationOptions& io):Interpolation(io) + { + } + //================================================================================ /*! * \brief An 1D intersection result diff --git a/src/INTERP_KERNEL/InterpolationCU.txx b/src/INTERP_KERNEL/InterpolationCU.txx index f9528e185..af2cf5fae 100644 --- a/src/INTERP_KERNEL/InterpolationCU.txx +++ b/src/INTERP_KERNEL/InterpolationCU.txx @@ -148,7 +148,7 @@ namespace INTERP_KERNEL bool doItersect = true; for ( int j = 0; j < dim && doItersect; ++j ) doItersect = - bb[j*2] < src_coords[j][ src_nb_coords[0]-1 ] - eps && + bb[j*2] < src_coords[j][ src_nb_coords[j]-1 ] - eps && bb[j*2+1] > src_coords[j][0] + eps; if ( !doItersect ) continue; // no intersection diff --git a/src/INTERP_KERNEL/TetraAffineTransform.cxx b/src/INTERP_KERNEL/TetraAffineTransform.cxx index 5c8ac1b6e..0ca3f599e 100644 --- a/src/INTERP_KERNEL/TetraAffineTransform.cxx +++ b/src/INTERP_KERNEL/TetraAffineTransform.cxx @@ -253,9 +253,9 @@ namespace INTERP_KERNEL // form standard base vector i const double b[3] = { - int(i == 0), - int(i == 1), - int(i == 2) + double ( int(i == 0) ), + double ( int(i == 1) ), + double ( int(i == 2) ), }; LOG(6, "b = [" << b[0] << ", " << b[1] << ", " << b[2] << "]"); diff --git a/src/INTERP_KERNEL/VolSurfFormulae.hxx b/src/INTERP_KERNEL/VolSurfFormulae.hxx index b7ad4fdb5..c59737068 100644 --- a/src/INTERP_KERNEL/VolSurfFormulae.hxx +++ b/src/INTERP_KERNEL/VolSurfFormulae.hxx @@ -22,7 +22,10 @@ #define __VOLSURFFORMULAE_HXX__ #include "InterpolationUtils.hxx" +#include "InterpKernelException.hxx" +#include "InterpKernelGeo2DQuadraticPolygon.hxx" +#include #include namespace INTERP_KERNEL @@ -34,6 +37,9 @@ namespace INTERP_KERNEL int spaceDim); + inline double calculateAreaForQPolyg(const double **coords, int nbOfPtsInPolygs, + int spaceDim); + inline double calculateLgthForSeg2(const double *p1, const double *p2, int spaceDim) { if(spaceDim==1) @@ -199,6 +205,31 @@ namespace INTERP_KERNEL return ret; } + double calculateAreaForQPolyg(const double **coords, int nbOfPtsInPolygs, int spaceDim) + { + + if(nbOfPtsInPolygs%2==0) + { + if(spaceDim==2) + { + std::vector nodes(nbOfPtsInPolygs); + for(int i=0;igetArea(); + delete pol; + return -ret; + } + else + return calculateAreaForPolyg(coords,nbOfPtsInPolygs/2,spaceDim); + } + else + { + std::ostringstream oss; oss << "INTERP_KERNEL::calculateAreaForQPolyg : nb of points in quadratic polygon is " << nbOfPtsInPolygs << " should be even !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + // ========================== // Calculate Volume for Tetra // ========================== diff --git a/src/INTERP_KERNEL/VolSurfUser.txx b/src/INTERP_KERNEL/VolSurfUser.txx index 5e4f6129d..adfb96552 100644 --- a/src/INTERP_KERNEL/VolSurfUser.txx +++ b/src/INTERP_KERNEL/VolSurfUser.txx @@ -42,8 +42,6 @@ namespace INTERP_KERNEL return INTERP_KERNEL::calculateLgthForSeg2(coords+(SPACEDIM*N1),coords+(SPACEDIM*N2),SPACEDIM); } case INTERP_KERNEL::NORM_TRI3 : - case INTERP_KERNEL::NORM_TRI6 : - case INTERP_KERNEL::NORM_TRI7 : { int N1 = OTT::coo2C(connec[0]); int N2 = OTT::coo2C(connec[1]); @@ -56,9 +54,20 @@ namespace INTERP_KERNEL } break; + case INTERP_KERNEL::NORM_TRI6 : + case INTERP_KERNEL::NORM_TRI7 : + { + const double *pts[6]; + pts[0] = coords+SPACEDIM*OTT::coo2C(connec[0]); + pts[1] = coords+SPACEDIM*OTT::coo2C(connec[1]); + pts[2] = coords+SPACEDIM*OTT::coo2C(connec[2]); + pts[3] = coords+SPACEDIM*OTT::coo2C(connec[3]); + pts[4] = coords+SPACEDIM*OTT::coo2C(connec[4]); + pts[5] = coords+SPACEDIM*OTT::coo2C(connec[5]); + return INTERP_KERNEL::calculateAreaForQPolyg(pts,6,SPACEDIM); + } + break; case INTERP_KERNEL::NORM_QUAD4 : - case INTERP_KERNEL::NORM_QUAD8 : - case INTERP_KERNEL::NORM_QUAD9 : { int N1 = OTT::coo2C(connec[0]); int N2 = OTT::coo2C(connec[1]); @@ -72,7 +81,21 @@ namespace INTERP_KERNEL SPACEDIM); } break; - + case INTERP_KERNEL::NORM_QUAD8 : + case INTERP_KERNEL::NORM_QUAD9 : + { + const double *pts[8]; + pts[0] = coords+SPACEDIM*OTT::coo2C(connec[0]); + pts[1] = coords+SPACEDIM*OTT::coo2C(connec[1]); + pts[2] = coords+SPACEDIM*OTT::coo2C(connec[2]); + pts[3] = coords+SPACEDIM*OTT::coo2C(connec[3]); + pts[4] = coords+SPACEDIM*OTT::coo2C(connec[4]); + pts[5] = coords+SPACEDIM*OTT::coo2C(connec[5]); + pts[6] = coords+SPACEDIM*OTT::coo2C(connec[6]); + pts[7] = coords+SPACEDIM*OTT::coo2C(connec[7]); + return INTERP_KERNEL::calculateAreaForQPolyg(pts,8,SPACEDIM); + } + break; case INTERP_KERNEL::NORM_POLYGON : { const double **pts=new const double *[lgth]; @@ -83,6 +106,15 @@ namespace INTERP_KERNEL return val; } break; + case INTERP_KERNEL::NORM_QPOLYG : + { + const double **pts=new const double *[lgth]; + for(int inod=0;inod::coo2C(connec[inod]); + double val=INTERP_KERNEL::calculateAreaForQPolyg(pts,lgth,SPACEDIM); + delete [] pts; + return val; + } case INTERP_KERNEL::NORM_TETRA4 : case INTERP_KERNEL::NORM_TETRA10 : { diff --git a/src/INTERP_KERNELTest/SingleElementPlanarTests.cxx b/src/INTERP_KERNELTest/SingleElementPlanarTests.cxx index a8b13882e..64e07e045 100644 --- a/src/INTERP_KERNELTest/SingleElementPlanarTests.cxx +++ b/src/INTERP_KERNELTest/SingleElementPlanarTests.cxx @@ -230,6 +230,9 @@ namespace INTERP_TEST void SingleElementPlanarTests::identicalSquares() { INTERP_KERNEL::PolygonAlgorithms<2> intersector (_Epsilon, _Precision);; + /* + ////////////////// TEST DESACTIVATED by A. GEAY because memory fault : + // conditional jump INTERP_KERNEL::PolygonAlgorithms<2>::intersectConvexPolygons(double const*, double const*, int, int) (PolygonAlgorithms.txx:629) std::deque< double > actual_result = intersector.intersectConvexPolygons(_square1,_square1,4,4); std::deque< double > expected_result; @@ -240,6 +243,7 @@ namespace INTERP_TEST CPPUNIT_ASSERT_MESSAGE("Identical squares test failed (CONVEX)", (INTERP_KERNEL::checkEqualPolygons,2>(&actual_result, &expected_result, _Epsilon))); + */ } void SingleElementPlanarTests::identicalSquares_Triangulation() { diff --git a/src/INTERP_KERNELTest/UnitTetra3D2DIntersectionTest.cxx b/src/INTERP_KERNELTest/UnitTetra3D2DIntersectionTest.cxx index 366d40ca6..b4511ea1c 100644 --- a/src/INTERP_KERNELTest/UnitTetra3D2DIntersectionTest.cxx +++ b/src/INTERP_KERNELTest/UnitTetra3D2DIntersectionTest.cxx @@ -74,7 +74,7 @@ namespace INTERP_TEST precision, listOfTetraFacesTreated, listOfTetraFacesColinear); - + delete targetTetra; CPPUNIT_ASSERT_DOUBLES_EQUAL(40.,surface,precision); CPPUNIT_ASSERT_EQUAL(4,(int)listOfTetraFacesTreated.size()); @@ -120,7 +120,7 @@ namespace INTERP_TEST precision, listOfTetraFacesTreated, listOfTetraFacesColinear); - + delete targetTetra; CPPUNIT_ASSERT_DOUBLES_EQUAL(40.,surface,precision); CPPUNIT_ASSERT_EQUAL(4,(int)listOfTetraFacesTreated.size()); @@ -165,7 +165,7 @@ namespace INTERP_TEST precision, listOfTetraFacesTreated, listOfTetraFacesColinear); - + delete targetTetra; CPPUNIT_ASSERT_DOUBLES_EQUAL(2.5,surface,precision); CPPUNIT_ASSERT_EQUAL(0,(int)listOfTetraFacesTreated.size()); diff --git a/src/MEDCoupling/MEDCouplingCMesh.cxx b/src/MEDCoupling/MEDCouplingCMesh.cxx index bd6233b93..2276b4d28 100644 --- a/src/MEDCoupling/MEDCouplingCMesh.cxx +++ b/src/MEDCoupling/MEDCouplingCMesh.cxx @@ -519,6 +519,8 @@ DataArrayDouble *MEDCouplingCMesh::getCoordsAt(int i) throw(INTERP_KERNEL::Excep void MEDCouplingCMesh::setCoordsAt(int i, const DataArrayDouble *arr) throw(INTERP_KERNEL::Exception) { + if(arr) + arr->checkNbOfComps(1,"MEDCouplingCMesh::setCoordsAt"); DataArrayDouble **thisArr[3]={&_x_array,&_y_array,&_z_array}; if(i<0 || i>2) throw INTERP_KERNEL::Exception("Invalid rank specified must be 0 or 1 or 2."); @@ -535,6 +537,12 @@ void MEDCouplingCMesh::setCoordsAt(int i, const DataArrayDouble *arr) throw(INTE void MEDCouplingCMesh::setCoords(const DataArrayDouble *coordsX, const DataArrayDouble *coordsY, const DataArrayDouble *coordsZ) { + if(coordsX) + coordsX->checkNbOfComps(1,"MEDCouplingCMesh::setCoords : coordsX"); + if(coordsY) + coordsY->checkNbOfComps(1,"MEDCouplingCMesh::setCoords : coordsY"); + if(coordsZ) + coordsZ->checkNbOfComps(1,"MEDCouplingCMesh::setCoords : coordsZ"); if(_x_array) _x_array->decrRef(); _x_array=const_cast(coordsX); diff --git a/src/MEDCoupling/MEDCouplingField.cxx b/src/MEDCoupling/MEDCouplingField.cxx index 08eb6970b..805b4a7c5 100644 --- a/src/MEDCoupling/MEDCouplingField.cxx +++ b/src/MEDCoupling/MEDCouplingField.cxx @@ -260,6 +260,13 @@ int MEDCouplingField::getGaussLocalizationIdOfOneType(INTERP_KERNEL::NormalizedC return _type->getGaussLocalizationIdOfOneType(type); } +std::set MEDCouplingField::getGaussLocalizationIdsOfOneType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception) +{ + if(!_mesh) + throw INTERP_KERNEL::Exception("Mesh has to be set before calling getGaussLocalizationIdsOfOneType method !"); + return _type->getGaussLocalizationIdsOfOneType(type); +} + /*! * This method returns number of Gauss localization available. Implicitely all ids in [0,getNbOfGaussLocalization()) is a valid Gauss localisation id. * This method throws an exception if there is no mesh, invalid FieldDescription (different from Gauss) diff --git a/src/MEDCoupling/MEDCouplingField.hxx b/src/MEDCoupling/MEDCouplingField.hxx index 439743ad5..69e6752ee 100644 --- a/src/MEDCoupling/MEDCouplingField.hxx +++ b/src/MEDCoupling/MEDCouplingField.hxx @@ -65,6 +65,7 @@ namespace ParaMEDMEM DataArrayInt *computeTupleIdsToSelectFromCellIds(const int *startCellIds, const int *endCellIds) const; const MEDCouplingFieldDiscretization *getDiscretization() const { return _type; } MEDCouplingFieldDiscretization *getDiscretization() { return _type; } + void setDiscretization(MEDCouplingFieldDiscretization *newDisc) { _type=newDisc; } int getNumberOfTuplesExpected() const throw(INTERP_KERNEL::Exception); int getNumberOfMeshPlacesExpected() const throw(INTERP_KERNEL::Exception); // Gauss point specific methods @@ -75,6 +76,7 @@ namespace ParaMEDMEM void clearGaussLocalizations(); MEDCouplingGaussLocalization& getGaussLocalization(int locId) throw(INTERP_KERNEL::Exception); int getGaussLocalizationIdOfOneType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception); + std::set getGaussLocalizationIdsOfOneType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception); int getNbOfGaussLocalization() const throw(INTERP_KERNEL::Exception); int getGaussLocalizationIdOfOneCell(int cellId) const throw(INTERP_KERNEL::Exception); void getCellIdsHavingGaussLocalization(int locId, std::vector& cellIds) const throw(INTERP_KERNEL::Exception); diff --git a/src/MEDCoupling/MEDCouplingFieldDiscretization.cxx b/src/MEDCoupling/MEDCouplingFieldDiscretization.cxx index 2739ca421..80b9d6a63 100644 --- a/src/MEDCoupling/MEDCouplingFieldDiscretization.cxx +++ b/src/MEDCoupling/MEDCouplingFieldDiscretization.cxx @@ -113,6 +113,14 @@ bool MEDCouplingFieldDiscretization::isEqualWithoutConsideringStr(const MEDCoupl return isEqual(other,eps); } +/*! + * For all field discretization excepted GaussPts the [ \a startCellIds, \a endCellIds ) has no impact on the cloned instance. + */ +MEDCouplingFieldDiscretization *MEDCouplingFieldDiscretization::clonePart(const int *startCellIds, const int *endCellIds) const +{ + return clone(); +} + /*! * Excepted for MEDCouplingFieldDiscretizationPerCell no underlying TimeLabel object : nothing to do in generally. */ @@ -281,16 +289,21 @@ int MEDCouplingFieldDiscretization::getGaussLocalizationIdOfOneType(INTERP_KERNE throw INTERP_KERNEL::Exception("Invalid method for the corresponding field discretization : available only for GaussPoint discretization !"); } +std::set MEDCouplingFieldDiscretization::getGaussLocalizationIdsOfOneType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception) +{ + throw INTERP_KERNEL::Exception("Invalid method for the corresponding field discretization : available only for GaussPoint discretization !"); +} + void MEDCouplingFieldDiscretization::getCellIdsHavingGaussLocalization(int locId, std::vector& cellIds) const throw(INTERP_KERNEL::Exception) { throw INTERP_KERNEL::Exception("Invalid method for the corresponding field discretization : available only for GaussPoint discretization !"); } -void MEDCouplingFieldDiscretization::renumberEntitiesFromO2NArr(double eps, const int *old2NewPtr, DataArrayDouble *arr, const char *msg) +void MEDCouplingFieldDiscretization::RenumberEntitiesFromO2NArr(double eps, const int *old2NewPtr, int newNbOfEntity, DataArrayDouble *arr, const char *msg) { int oldNbOfElems=arr->getNumberOfTuples(); int nbOfComp=arr->getNumberOfComponents(); - int newNbOfTuples=(*std::max_element(old2NewPtr,old2NewPtr+oldNbOfElems))+1; + int newNbOfTuples=newNbOfEntity; DataArrayDouble *arrCpy=arr->deepCpy(); const double *ptSrc=arrCpy->getConstPointer(); arr->reAlloc(newNbOfTuples); @@ -324,7 +337,7 @@ void MEDCouplingFieldDiscretization::renumberEntitiesFromO2NArr(double eps, cons arrCpy->decrRef(); } -void MEDCouplingFieldDiscretization::renumberEntitiesFromN2OArr(const int *new2OldPtr, int new2OldSz, DataArrayDouble *arr, const char *msg) +void MEDCouplingFieldDiscretization::RenumberEntitiesFromN2OArr(const int *new2OldPtr, int new2OldSz, DataArrayDouble *arr, const char *msg) { int nbOfComp=arr->getNumberOfComponents(); DataArrayDouble *arrCpy=arr->deepCpy(); @@ -482,18 +495,18 @@ DataArrayDouble *MEDCouplingFieldDiscretizationP0::getValueOnMulti(const DataArr /*! * Nothing to do. It's not a bug. */ -void MEDCouplingFieldDiscretizationP0::renumberValuesOnNodes(double , const int *, DataArrayDouble *) const +void MEDCouplingFieldDiscretizationP0::renumberValuesOnNodes(double , const int *, int newNbOfNodes, DataArrayDouble *) const { } -void MEDCouplingFieldDiscretizationP0::renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, DataArrayDouble *arr) const +void MEDCouplingFieldDiscretizationP0::renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, int newSz, DataArrayDouble *arr) const { - renumberEntitiesFromO2NArr(epsOnVals,old2New,arr,"Cell"); + RenumberEntitiesFromO2NArr(epsOnVals,old2New,newSz,arr,"Cell"); } void MEDCouplingFieldDiscretizationP0::renumberValuesOnCellsR(const MEDCouplingMesh *mesh, const int *new2old, int newSz, DataArrayDouble *arr) const { - renumberEntitiesFromN2OArr(new2old,newSz,arr,"Cell"); + RenumberEntitiesFromN2OArr(new2old,newSz,arr,"Cell"); } /*! @@ -607,15 +620,15 @@ DataArrayInt *MEDCouplingFieldDiscretizationOnNodes::computeTupleIdsToSelectFrom return umesh2->computeFetchedNodeIds(); } -void MEDCouplingFieldDiscretizationOnNodes::renumberValuesOnNodes(double epsOnVals, const int *old2NewPtr, DataArrayDouble *arr) const +void MEDCouplingFieldDiscretizationOnNodes::renumberValuesOnNodes(double epsOnVals, const int *old2NewPtr, int newNbOfNodes, DataArrayDouble *arr) const { - renumberEntitiesFromO2NArr(epsOnVals,old2NewPtr,arr,"Node"); + RenumberEntitiesFromO2NArr(epsOnVals,old2NewPtr,newNbOfNodes,arr,"Node"); } /*! * Nothing to do it's not a bug. */ -void MEDCouplingFieldDiscretizationOnNodes::renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, DataArrayDouble *arr) const +void MEDCouplingFieldDiscretizationOnNodes::renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, int newSz, DataArrayDouble *arr) const { } @@ -748,11 +761,16 @@ MEDCouplingFieldDiscretizationPerCell::~MEDCouplingFieldDiscretizationPerCell() _discr_per_cell->decrRef(); } -MEDCouplingFieldDiscretizationPerCell::MEDCouplingFieldDiscretizationPerCell(const MEDCouplingFieldDiscretizationPerCell& other):_discr_per_cell(0) +MEDCouplingFieldDiscretizationPerCell::MEDCouplingFieldDiscretizationPerCell(const MEDCouplingFieldDiscretizationPerCell& other, const int *startCellIds, const int *endCellIds):_discr_per_cell(0) { DataArrayInt *arr=other._discr_per_cell; if(arr) - _discr_per_cell=arr->deepCpy(); + { + if(startCellIds==0 && endCellIds==0) + _discr_per_cell=arr->deepCpy(); + else + _discr_per_cell=arr->selectByTupleIdSafe(startCellIds,endCellIds); + } } void MEDCouplingFieldDiscretizationPerCell::updateTime() const @@ -849,7 +867,7 @@ MEDCouplingFieldDiscretizationGauss::MEDCouplingFieldDiscretizationGauss() { } -MEDCouplingFieldDiscretizationGauss::MEDCouplingFieldDiscretizationGauss(const MEDCouplingFieldDiscretizationGauss& other):MEDCouplingFieldDiscretizationPerCell(other),_loc(other._loc) +MEDCouplingFieldDiscretizationGauss::MEDCouplingFieldDiscretizationGauss(const MEDCouplingFieldDiscretizationGauss& other, const int *startCellIds, const int *endCellIds):MEDCouplingFieldDiscretizationPerCell(other,startCellIds,endCellIds),_loc(other._loc) { } @@ -905,6 +923,11 @@ MEDCouplingFieldDiscretization *MEDCouplingFieldDiscretizationGauss::clone() con return new MEDCouplingFieldDiscretizationGauss(*this); } +MEDCouplingFieldDiscretization *MEDCouplingFieldDiscretizationGauss::clonePart(const int *startCellIds, const int *endCellIds) const +{ + return new MEDCouplingFieldDiscretizationGauss(*this,startCellIds,endCellIds); +} + std::string MEDCouplingFieldDiscretizationGauss::getStringRepr() const { std::ostringstream oss; oss << REPR << "." << std::endl; @@ -951,13 +974,25 @@ int MEDCouplingFieldDiscretizationGauss::getNumberOfMeshPlaces(const MEDCoupling DataArrayInt *MEDCouplingFieldDiscretizationGauss::getOffsetArr(const MEDCouplingMesh *mesh) const { int nbOfTuples=mesh->getNumberOfCells(); - DataArrayInt *ret=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); ret->alloc(nbOfTuples+1,1); int *retPtr=ret->getPointer(); const int *start=_discr_per_cell->getConstPointer(); + if(_discr_per_cell->getNumberOfTuples()!=nbOfTuples) + throw INTERP_KERNEL::Exception("MEDCouplingFieldDiscretizationGauss::getOffsetArr : mismatch between the mesh and the discretization ids array length !"); + int maxPossible=(int)_loc.size(); retPtr[0]=0; for(int i=0;i=0 && *startincrRef(); return ret; } @@ -999,7 +1034,7 @@ DataArrayDouble *MEDCouplingFieldDiscretizationGauss::getLocalizationOfDiscValue DataArrayDouble *ret=DataArrayDouble::New(); int spaceDim=mesh->getSpaceDimension(); ret->alloc(nbOfTuples,spaceDim); - std::vector< std::vector > locIds; + std::vector< int > locIds; std::vector parts=splitIntoSingleGaussDicrPerCellType(locIds); std::vector< MEDCouplingAutoRefCountObjectPtr > parts2(parts.size()); std::copy(parts.begin(),parts.end(),parts2.begin()); @@ -1013,21 +1048,17 @@ DataArrayDouble *MEDCouplingFieldDiscretizationGauss::getLocalizationOfDiscValue for(std::size_t i=0;i::const_iterator it=locIds[i].begin();it!=locIds[i].end();it++) - { - const MEDCouplingGaussLocalization& cli=_loc[*it];//curLocInfo - INTERP_KERNEL::NormalizedCellType typ=cli.getType(); - const std::vector& wg=cli.getWeights(); - calculator.addGaussInfo(typ,INTERP_KERNEL::CellModel::GetCellModel(typ).getDimension(), + // + const MEDCouplingGaussLocalization& cli=_loc[locIds[i]];//curLocInfo + INTERP_KERNEL::NormalizedCellType typ=cli.getType(); + const std::vector& wg=cli.getWeights(); + calculator.addGaussInfo(typ,INTERP_KERNEL::CellModel::GetCellModel(typ).getDimension(), &cli.getGaussCoords()[0],(int)wg.size(),&cli.getRefCoords()[0], INTERP_KERNEL::CellModel::GetCellModel(typ).getNumberOfNodes()); - } + // int nbt=parts2[i]->getNumberOfTuples(); for(const int *w=parts2[i]->getConstPointer();w!=parts2[i]->getConstPointer()+nbt;w++) - { - const MEDCouplingGaussLocalization& cli=_loc[*w]; - calculator.calculateCoords(cli.getType(),coords,spaceDim,conn+connI[*w]+1,valsToFill+spaceDim*(ptrOffsets[*w])); - } + calculator.calculateCoords(cli.getType(),coords,spaceDim,conn+connI[*w]+1,valsToFill+spaceDim*(ptrOffsets[*w])); } ret->copyStringInfoFrom(*umesh->getCoords()); return ret; @@ -1196,7 +1227,7 @@ DataArrayInt *MEDCouplingFieldDiscretizationGauss::computeTupleIdsToSelectFromCe int *retPtr=nbOfNodesPerCell->getPointer(); const int *pt=_discr_per_cell->getConstPointer(); int nbMaxOfLocId=(int)_loc.size(); - for(int i=0;i=0 && *pt ret=getGaussLocalizationIdsOfOneType(type); + if(ret.empty()) + throw INTERP_KERNEL::Exception("No gauss discretization found for the specified type !"); + if(ret.size()>1) + throw INTERP_KERNEL::Exception("Several gauss discretizations have been found for the specified type !"); + return *ret.begin(); +} + +std::set MEDCouplingFieldDiscretizationGauss::getGaussLocalizationIdsOfOneType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception) { if(!_discr_per_cell) throw INTERP_KERNEL::Exception("No Gauss localization still set !"); @@ -1311,11 +1352,7 @@ int MEDCouplingFieldDiscretizationGauss::getGaussLocalizationIdOfOneType(INTERP_ for(std::vector::const_iterator iter=_loc.begin();iter!=_loc.end();iter++,id++) if((*iter).getType()==type) ret.insert(id); - if(ret.empty()) - throw INTERP_KERNEL::Exception("No gauss discretization found for the specified type !"); - if(ret.size()>1) - throw INTERP_KERNEL::Exception("Several gauss discretizations have been found for the specified type !"); - return *ret.begin(); + return ret; } void MEDCouplingFieldDiscretizationGauss::getCellIdsHavingGaussLocalization(int locId, std::vector& cellIds) const throw(INTERP_KERNEL::Exception) @@ -1383,8 +1420,8 @@ void MEDCouplingFieldDiscretizationGauss::zipGaussLocalizations() { const int *start=_discr_per_cell->getConstPointer(); int nbOfTuples=_discr_per_cell->getNumberOfTuples(); - int *tmp=new int[_loc.size()]; - std::fill(tmp,tmp+_loc.size(),-2); + INTERP_KERNEL::AutoPtr tmp=new int[_loc.size()]; + std::fill((int *)tmp,(int *)tmp+_loc.size(),-2); for(const int *w=start;w!=start+nbOfTuples;w++) if(*w>=0) tmp[*w]=1; @@ -1393,19 +1430,16 @@ void MEDCouplingFieldDiscretizationGauss::zipGaussLocalizations() if(tmp[i]!=-2) tmp[i]=fid++; if(fid==(int)_loc.size()) - {//no zip needed - delete [] tmp; - return; - } + return; // zip needed int *start2=_discr_per_cell->getPointer(); for(int *w2=start2;w2!=start2+nbOfTuples;w2++) - *w2=tmp[*w2]; + if(*w2>=0) + *w2=tmp[*w2]; std::vector tmpLoc; for(int i=0;i<(int)_loc.size();i++) if(tmp[i]!=-2) tmpLoc.push_back(_loc[tmp[i]]); - delete [] tmp; _loc=tmpLoc; } @@ -1419,56 +1453,11 @@ void MEDCouplingFieldDiscretizationGauss::zipGaussLocalizations() * * If no descretization is set in 'this' and exception will be thrown. */ -std::vector MEDCouplingFieldDiscretizationGauss::splitIntoSingleGaussDicrPerCellType(std::vector< std::vector >& locIds) const throw(INTERP_KERNEL::Exception) +std::vector MEDCouplingFieldDiscretizationGauss::splitIntoSingleGaussDicrPerCellType(std::vector& locIds) const throw(INTERP_KERNEL::Exception) { if(!_discr_per_cell) throw INTERP_KERNEL::Exception("MEDCouplingFieldDiscretizationGauss::splitIntoSingleGaussDicrPerCellType : no descretization set !"); - locIds.clear(); - std::vector ret; - const int *discrPerCell=_discr_per_cell->getConstPointer(); - MEDCouplingAutoRefCountObjectPtr ret2=_discr_per_cell->getIdsNotEqual(-1); - int nbOfTuplesSet=ret2->getNumberOfTuples(); - std::list idsRemaining(ret2->getConstPointer(),ret2->getConstPointer()+nbOfTuplesSet); - std::list::iterator it=idsRemaining.begin(); - while(it!=idsRemaining.end()) - { - std::vector ids; - std::set curLocIds; - std::set curCellTypes; - while(it!=idsRemaining.end()) - { - int curDiscrId=discrPerCell[*it]; - INTERP_KERNEL::NormalizedCellType typ=_loc[curDiscrId].getType(); - if(curCellTypes.find(typ)!=curCellTypes.end()) - { - if(curLocIds.find(curDiscrId)!=curLocIds.end()) - { - curLocIds.insert(curDiscrId); - curCellTypes.insert(typ); - ids.push_back(*it); - it=idsRemaining.erase(it); - } - else - it++; - } - else - { - curLocIds.insert(curDiscrId); - curCellTypes.insert(typ); - ids.push_back(*it); - it=idsRemaining.erase(it); - } - } - it=idsRemaining.begin(); - ret.resize(ret.size()+1); - DataArrayInt *part=DataArrayInt::New(); - part->alloc((int)ids.size(),1); - std::copy(ids.begin(),ids.end(),part->getPointer()); - ret.back()=part; - locIds.resize(locIds.size()+1); - locIds.back().insert(locIds.back().end(),curLocIds.begin(),curLocIds.end()); - } - return ret; + return _discr_per_cell->partitionByDifferentValues(locIds); } MEDCouplingFieldDiscretizationGaussNE::MEDCouplingFieldDiscretizationGaussNE() @@ -1661,11 +1650,11 @@ DataArrayInt *MEDCouplingFieldDiscretizationGaussNE::computeTupleIdsToSelectFrom /*! * No implementation needed ! */ -void MEDCouplingFieldDiscretizationGaussNE::renumberValuesOnNodes(double , const int *, DataArrayDouble *) const +void MEDCouplingFieldDiscretizationGaussNE::renumberValuesOnNodes(double , const int *, int newNbOfNodes, DataArrayDouble *) const { } -void MEDCouplingFieldDiscretizationGaussNE::renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, DataArrayDouble *arr) const +void MEDCouplingFieldDiscretizationGaussNE::renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, int newSz, DataArrayDouble *arr) const { throw INTERP_KERNEL::Exception("Not implemented yet !"); } @@ -1774,7 +1763,7 @@ DataArrayDouble *MEDCouplingFieldDiscretizationKriging::computeVectorOfCoefficie { MEDCouplingAutoRefCountObjectPtr coords=getLocalizationOfDiscValues(mesh); int nbOfPts=coords->getNumberOfTuples(); - int dimension=coords->getNumberOfComponents(); + //int dimension=coords->getNumberOfComponents(); MEDCouplingAutoRefCountObjectPtr matrix=coords->buildEuclidianDistanceDenseMatrix(); operateOnDenseMatrix(mesh->getSpaceDimension(),nbOfPts*nbOfPts,matrix->getPointer()); // Drift diff --git a/src/MEDCoupling/MEDCouplingFieldDiscretization.hxx b/src/MEDCoupling/MEDCouplingFieldDiscretization.hxx index df43d9527..6efe4aae1 100644 --- a/src/MEDCoupling/MEDCouplingFieldDiscretization.hxx +++ b/src/MEDCoupling/MEDCouplingFieldDiscretization.hxx @@ -29,6 +29,7 @@ #include "MEDCouplingGaussLocalization.hxx" #include "MEDCouplingAutoRefCountObjectPtr.hxx" +#include #include namespace ParaMEDMEM @@ -51,6 +52,7 @@ namespace ParaMEDMEM virtual bool isEqualIfNotWhy(const MEDCouplingFieldDiscretization *other, double eps, std::string& reason) const = 0; virtual bool isEqualWithoutConsideringStr(const MEDCouplingFieldDiscretization *other, double eps) const; virtual MEDCouplingFieldDiscretization *clone() const = 0; + virtual MEDCouplingFieldDiscretization *clonePart(const int *startCellIds, const int *endCellIds) const; virtual std::string getStringRepr() const = 0; virtual const char *getRepr() const = 0; virtual int getNumberOfTuples(const MEDCouplingMesh *mesh) const = 0; @@ -74,8 +76,8 @@ namespace ParaMEDMEM virtual DataArrayDouble *getValueOnMulti(const DataArrayDouble *arr, const MEDCouplingMesh *mesh, const double *loc, int nbOfPoints) const = 0; virtual DataArrayInt *computeTupleIdsToSelectFromCellIds(const MEDCouplingMesh *mesh, const int *startCellIds, const int *endCellIds) const = 0; virtual MEDCouplingMesh *buildSubMeshData(const MEDCouplingMesh *mesh, const int *start, const int *end, DataArrayInt *&di) const = 0; - virtual void renumberValuesOnNodes(double epsOnVals, const int *old2New, DataArrayDouble *arr) const = 0; - virtual void renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, DataArrayDouble *arr) const = 0; + virtual void renumberValuesOnNodes(double epsOnVals, const int *old2New, int newNbOfNodes, DataArrayDouble *arr) const = 0; + virtual void renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, int newSz, DataArrayDouble *arr) const = 0; virtual void renumberValuesOnCellsR(const MEDCouplingMesh *mesh, const int *new2old, int newSz, DataArrayDouble *arr) const = 0; virtual void getSerializationIntArray(DataArrayInt *& arr) const; virtual void getTinySerializationIntInformation(std::vector& tinyInfo) const; @@ -91,13 +93,14 @@ namespace ParaMEDMEM virtual int getNbOfGaussLocalization() const throw(INTERP_KERNEL::Exception); virtual int getGaussLocalizationIdOfOneCell(int cellId) const throw(INTERP_KERNEL::Exception); virtual int getGaussLocalizationIdOfOneType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception); + virtual std::set getGaussLocalizationIdsOfOneType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception); virtual void getCellIdsHavingGaussLocalization(int locId, std::vector& cellIds) const throw(INTERP_KERNEL::Exception); virtual const MEDCouplingGaussLocalization& getGaussLocalization(int locId) const throw(INTERP_KERNEL::Exception); virtual ~MEDCouplingFieldDiscretization(); protected: MEDCouplingFieldDiscretization(); - static void renumberEntitiesFromO2NArr(double epsOnVals, const int *old2NewPtr, DataArrayDouble *arr, const char *msg); - static void renumberEntitiesFromN2OArr(const int *new2OldPtr, int new2OldSz, DataArrayDouble *arr, const char *msg); + static void RenumberEntitiesFromO2NArr(double epsOnVals, const int *old2NewPtr, int newNbOfEntity, DataArrayDouble *arr, const char *msg); + static void RenumberEntitiesFromN2OArr(const int *new2OldPtr, int new2OldSz, DataArrayDouble *arr, const char *msg); protected: double _precision; static const double DFLT_PRECISION; @@ -125,8 +128,8 @@ namespace ParaMEDMEM void getValueOn(const DataArrayDouble *arr, const MEDCouplingMesh *mesh, const double *loc, double *res) const; void getValueOnPos(const DataArrayDouble *arr, const MEDCouplingMesh *mesh, int i, int j, int k, double *res) const; DataArrayDouble *getValueOnMulti(const DataArrayDouble *arr, const MEDCouplingMesh *mesh, const double *loc, int nbOfPoints) const; - void renumberValuesOnNodes(double epsOnVals, const int *old2New, DataArrayDouble *arr) const; - void renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, DataArrayDouble *arr) const; + void renumberValuesOnNodes(double epsOnVals, const int *old2New, int newNbOfNodes, DataArrayDouble *arr) const; + void renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, int newSz, DataArrayDouble *arr) const; void renumberValuesOnCellsR(const MEDCouplingMesh *mesh, const int *new2old, int newSz, DataArrayDouble *arr) const; MEDCouplingMesh *buildSubMeshData(const MEDCouplingMesh *mesh, const int *start, const int *end, DataArrayInt *&di) const; DataArrayInt *computeTupleIdsToSelectFromCellIds(const MEDCouplingMesh *mesh, const int *startCellIds, const int *endCellIds) const; @@ -149,8 +152,8 @@ namespace ParaMEDMEM void checkCoherencyBetween(const MEDCouplingMesh *mesh, const DataArrayDouble *da) const throw(INTERP_KERNEL::Exception); MEDCouplingMesh *buildSubMeshData(const MEDCouplingMesh *mesh, const int *start, const int *end, DataArrayInt *&di) const; DataArrayInt *computeTupleIdsToSelectFromCellIds(const MEDCouplingMesh *mesh, const int *startCellIds, const int *endCellIds) const; - void renumberValuesOnNodes(double epsOnVals, const int *old2New, DataArrayDouble *arr) const; - void renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, DataArrayDouble *arr) const; + void renumberValuesOnNodes(double epsOnVals, const int *old2New, int newNbOfNodes, DataArrayDouble *arr) const; + void renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, int newSz, DataArrayDouble *arr) const; void renumberValuesOnCellsR(const MEDCouplingMesh *mesh, const int *new2old, int newSz, DataArrayDouble *arr) const; public: void getValueOnPos(const DataArrayDouble *arr, const MEDCouplingMesh *mesh, int i, int j, int k, double *res) const; @@ -185,7 +188,7 @@ namespace ParaMEDMEM const DataArrayInt *getArrayOfDiscIds() const; protected: MEDCouplingFieldDiscretizationPerCell(); - MEDCouplingFieldDiscretizationPerCell(const MEDCouplingFieldDiscretizationPerCell& other); + MEDCouplingFieldDiscretizationPerCell(const MEDCouplingFieldDiscretizationPerCell& other, const int *startCellIds, const int *endCellIds); ~MEDCouplingFieldDiscretizationPerCell(); void updateTime() const; void checkCoherencyBetween(const MEDCouplingMesh *mesh, const DataArrayDouble *da) const throw(INTERP_KERNEL::Exception); @@ -208,6 +211,7 @@ namespace ParaMEDMEM bool isEqualIfNotWhy(const MEDCouplingFieldDiscretization *other, double eps, std::string& reason) const; bool isEqualWithoutConsideringStr(const MEDCouplingFieldDiscretization *other, double eps) const; MEDCouplingFieldDiscretization *clone() const; + MEDCouplingFieldDiscretization *clonePart(const int *startCellIds, const int *endCellIds) const; std::string getStringRepr() const; const char *getRepr() const; int getNumberOfTuples(const MEDCouplingMesh *mesh) const; @@ -232,8 +236,8 @@ namespace ParaMEDMEM DataArrayDouble *getValueOnMulti(const DataArrayDouble *arr, const MEDCouplingMesh *mesh, const double *loc, int nbOfPoints) const; MEDCouplingMesh *buildSubMeshData(const MEDCouplingMesh *mesh, const int *start, const int *end, DataArrayInt *&di) const; DataArrayInt *computeTupleIdsToSelectFromCellIds(const MEDCouplingMesh *mesh, const int *startCellIds, const int *endCellIds) const; - void renumberValuesOnNodes(double epsOnVals, const int *old2New, DataArrayDouble *arr) const; - void renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, DataArrayDouble *arr) const; + void renumberValuesOnNodes(double epsOnVals, const int *old2New, int newNbOfNodes, DataArrayDouble *arr) const; + void renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, int newSz, DataArrayDouble *arr) const; void renumberValuesOnCellsR(const MEDCouplingMesh *mesh, const int *new2old, int newSz, DataArrayDouble *arr) const; void setGaussLocalizationOnType(const MEDCouplingMesh *m, INTERP_KERNEL::NormalizedCellType type, const std::vector& refCoo, const std::vector& gsCoo, const std::vector& wg) throw(INTERP_KERNEL::Exception); @@ -244,12 +248,13 @@ namespace ParaMEDMEM int getNbOfGaussLocalization() const throw(INTERP_KERNEL::Exception); int getGaussLocalizationIdOfOneCell(int cellId) const throw(INTERP_KERNEL::Exception); int getGaussLocalizationIdOfOneType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception); + std::set getGaussLocalizationIdsOfOneType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception); void getCellIdsHavingGaussLocalization(int locId, std::vector& cellIds) const throw(INTERP_KERNEL::Exception); const MEDCouplingGaussLocalization& getGaussLocalization(int locId) const throw(INTERP_KERNEL::Exception); - std::vector splitIntoSingleGaussDicrPerCellType(std::vector< std::vector >& locIds) const throw(INTERP_KERNEL::Exception); + std::vector splitIntoSingleGaussDicrPerCellType(std::vector< int >& locIds) const throw(INTERP_KERNEL::Exception); DataArrayInt *buildNbOfGaussPointPerCellField() const throw(INTERP_KERNEL::Exception); protected: - MEDCouplingFieldDiscretizationGauss(const MEDCouplingFieldDiscretizationGauss& other); + MEDCouplingFieldDiscretizationGauss(const MEDCouplingFieldDiscretizationGauss& other, const int *startCellIds=0, const int *endCellIds=0); void zipGaussLocalizations(); int getOffsetOfCell(int cellId) const throw(INTERP_KERNEL::Exception); void checkLocalizationId(int locId) const throw(INTERP_KERNEL::Exception); @@ -289,8 +294,8 @@ namespace ParaMEDMEM DataArrayDouble *getValueOnMulti(const DataArrayDouble *arr, const MEDCouplingMesh *mesh, const double *loc, int nbOfPoints) const; MEDCouplingMesh *buildSubMeshData(const MEDCouplingMesh *mesh, const int *start, const int *end, DataArrayInt *&di) const; DataArrayInt *computeTupleIdsToSelectFromCellIds(const MEDCouplingMesh *mesh, const int *startCellIds, const int *endCellIds) const; - void renumberValuesOnNodes(double epsOnVals, const int *old2New, DataArrayDouble *arr) const; - void renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, DataArrayDouble *arr) const; + void renumberValuesOnNodes(double epsOnVals, const int *old2New, int newNbOfNodes, DataArrayDouble *arr) const; + void renumberValuesOnCells(double epsOnVals, const MEDCouplingMesh *mesh, const int *old2New, int newSz, DataArrayDouble *arr) const; void renumberValuesOnCellsR(const MEDCouplingMesh *mesh, const int *new2old, int newSz, DataArrayDouble *arr) const; protected: MEDCouplingFieldDiscretizationGaussNE(const MEDCouplingFieldDiscretizationGaussNE& other); diff --git a/src/MEDCoupling/MEDCouplingFieldDouble.cxx b/src/MEDCoupling/MEDCouplingFieldDouble.cxx index 170cf2ecb..36c10e825 100644 --- a/src/MEDCoupling/MEDCouplingFieldDouble.cxx +++ b/src/MEDCoupling/MEDCouplingFieldDouble.cxx @@ -345,8 +345,9 @@ void MEDCouplingFieldDouble::renumberNodes(const int *old2NewBg) throw(INTERP_KE throw INTERP_KERNEL::Exception("Invalid mesh to apply renumberNodes on it !"); int nbOfNodes=meshC->getNumberOfNodes(); MEDCouplingAutoRefCountObjectPtr meshC2((MEDCouplingPointSet *)meshC->deepCpy()); - renumberNodesWithoutMesh(old2NewBg); - meshC2->renumberNodes(old2NewBg,*std::max_element(old2NewBg,old2NewBg+nbOfNodes)+1); + int newNbOfNodes=*std::max_element(old2NewBg,old2NewBg+nbOfNodes)+1; + renumberNodesWithoutMesh(old2NewBg,newNbOfNodes); + meshC2->renumberNodes(old2NewBg,newNbOfNodes); setMesh(meshC2); } @@ -355,13 +356,13 @@ void MEDCouplingFieldDouble::renumberNodes(const int *old2NewBg) throw(INTERP_KE * This method performs half job of MEDCouplingFieldDouble::renumberNodes. That is to say no permutation of cells is done on underlying mesh. * That is to say, the field content is changed by this method. */ -void MEDCouplingFieldDouble::renumberNodesWithoutMesh(const int *old2NewBg, double eps) throw(INTERP_KERNEL::Exception) +void MEDCouplingFieldDouble::renumberNodesWithoutMesh(const int *old2NewBg, int newNbOfNodes, double eps) throw(INTERP_KERNEL::Exception) { std::vector arrays; _time_discr->getArrays(arrays); for(std::vector::const_iterator iter=arrays.begin();iter!=arrays.end();iter++) if(*iter) - _type->renumberValuesOnNodes(eps,old2NewBg,*iter); + _type->renumberValuesOnNodes(eps,old2NewBg,newNbOfNodes,*iter); } /*! @@ -435,11 +436,13 @@ MEDCouplingFieldDouble *MEDCouplingFieldDouble::buildSubPart(const DataArrayInt MEDCouplingFieldDouble *MEDCouplingFieldDouble::buildSubPart(const int *partBg, const int *partEnd) const throw(INTERP_KERNEL::Exception) { DataArrayInt *arrSelect; - MEDCouplingMesh *m=_type->buildSubMeshData(_mesh,partBg,partEnd,arrSelect); + MEDCouplingAutoRefCountObjectPtr m=_type->buildSubMeshData(_mesh,partBg,partEnd,arrSelect); MEDCouplingAutoRefCountObjectPtr arrSelect2(arrSelect); MEDCouplingFieldDouble *ret=clone(false);//quick shallow copy. + const MEDCouplingFieldDiscretization *disc=getDiscretization(); + if(disc) + ret->setDiscretization(disc->clonePart(partBg,partEnd)); ret->setMesh(m); - m->decrRef(); std::vector arrays; _time_discr->getArrays(arrays); std::vector arrs; @@ -1196,18 +1199,13 @@ void MEDCouplingFieldDouble::changeUnderlyingMesh(const MEDCouplingMesh *other, { if(_mesh==0 || other==0) throw INTERP_KERNEL::Exception("MEDCouplingFieldDouble::changeUnderlyingMesh : is expected to operate on not null meshes !"); - DataArrayInt *cellCor,*nodeCor; + DataArrayInt *cellCor=0,*nodeCor=0; other->checkGeoEquivalWith(_mesh,levOfCheck,prec,cellCor,nodeCor); + MEDCouplingAutoRefCountObjectPtr cellCor2(cellCor),nodeCor2(nodeCor); if(cellCor) - { - renumberCellsWithoutMesh(cellCor->getConstPointer(),false); - cellCor->decrRef(); - } + renumberCellsWithoutMesh(cellCor->getConstPointer(),false); if(nodeCor) - { - renumberNodesWithoutMesh(nodeCor->getConstPointer()); - nodeCor->decrRef(); - } + renumberNodesWithoutMesh(nodeCor->getConstPointer(),_mesh->getNumberOfNodes()); setMesh(const_cast(other)); } @@ -1247,7 +1245,7 @@ bool MEDCouplingFieldDouble::mergeNodes(double eps, double epsOnVals) throw(INTE _time_discr->getArrays(arrays); for(std::vector::const_iterator iter=arrays.begin();iter!=arrays.end();iter++) if(*iter) - _type->renumberValuesOnNodes(epsOnVals,arr->getConstPointer(),*iter); + _type->renumberValuesOnNodes(epsOnVals,arr->getConstPointer(),meshC2->getNumberOfNodes(),*iter); setMesh(meshC2); return true; } @@ -1272,7 +1270,7 @@ bool MEDCouplingFieldDouble::mergeNodes2(double eps, double epsOnVals) throw(INT _time_discr->getArrays(arrays); for(std::vector::const_iterator iter=arrays.begin();iter!=arrays.end();iter++) if(*iter) - _type->renumberValuesOnNodes(epsOnVals,arr->getConstPointer(),*iter); + _type->renumberValuesOnNodes(epsOnVals,arr->getConstPointer(),meshC2->getNumberOfNodes(),*iter); setMesh(meshC2); return true; } @@ -1296,7 +1294,7 @@ bool MEDCouplingFieldDouble::zipCoords(double epsOnVals) throw(INTERP_KERNEL::Ex _time_discr->getArrays(arrays); for(std::vector::const_iterator iter=arrays.begin();iter!=arrays.end();iter++) if(*iter) - _type->renumberValuesOnNodes(epsOnVals,arr->getConstPointer(),*iter); + _type->renumberValuesOnNodes(epsOnVals,arr->getConstPointer(),meshC2->getNumberOfNodes(),*iter); setMesh(meshC2); return true; } @@ -1322,7 +1320,7 @@ bool MEDCouplingFieldDouble::zipConnectivity(int compType, double epsOnVals) thr _time_discr->getArrays(arrays); for(std::vector::const_iterator iter=arrays.begin();iter!=arrays.end();iter++) if(*iter) - _type->renumberValuesOnCells(epsOnVals,meshC,arr->getConstPointer(),*iter); + _type->renumberValuesOnCells(epsOnVals,meshC,arr->getConstPointer(),meshC2->getNumberOfCells(),*iter); setMesh(meshC2); return true; } diff --git a/src/MEDCoupling/MEDCouplingFieldDouble.hxx b/src/MEDCoupling/MEDCouplingFieldDouble.hxx index 3eac19dce..45a553b6b 100644 --- a/src/MEDCoupling/MEDCouplingFieldDouble.hxx +++ b/src/MEDCoupling/MEDCouplingFieldDouble.hxx @@ -51,7 +51,7 @@ namespace ParaMEDMEM void renumberCells(const int *old2NewBg, bool check=true) throw(INTERP_KERNEL::Exception); void renumberCellsWithoutMesh(const int *old2NewBg, bool check=true) throw(INTERP_KERNEL::Exception); void renumberNodes(const int *old2NewBg) throw(INTERP_KERNEL::Exception); - void renumberNodesWithoutMesh(const int *old2NewBg, double eps=1e-15) throw(INTERP_KERNEL::Exception); + void renumberNodesWithoutMesh(const int *old2NewBg, int newNbOfNodes, double eps=1e-15) throw(INTERP_KERNEL::Exception); DataArrayInt *getIdsInRange(double vmin, double vmax) const throw(INTERP_KERNEL::Exception); MEDCouplingFieldDouble *buildSubPart(const DataArrayInt *part) const throw(INTERP_KERNEL::Exception); MEDCouplingFieldDouble *buildSubPart(const int *partBg, const int *partEnd) const throw(INTERP_KERNEL::Exception); diff --git a/src/MEDCoupling/MEDCouplingMemArray.cxx b/src/MEDCoupling/MEDCouplingMemArray.cxx index a112e3eda..9081b8ecb 100644 --- a/src/MEDCoupling/MEDCouplingMemArray.cxx +++ b/src/MEDCoupling/MEDCouplingMemArray.cxx @@ -28,6 +28,7 @@ #include #include #include +#include #include typedef double (*MYFUNCPTR)(double); @@ -68,10 +69,9 @@ void DataArrayDouble::findCommonTuplesAlg(const double *bbox, int nbNodes, int l } template -void DataArrayDouble::findTupleIdsNearTuplesAlg(const BBTree& myTree, const double *pos, int nbOfTuples, double eps, - std::vector& c, std::vector& cI) const +void DataArrayDouble::FindTupleIdsNearTuplesAlg(const BBTree& myTree, const double *pos, int nbOfTuples, double eps, + std::vector& c, std::vector& cI) { - const double *coordsPtr=getConstPointer(); for(int i=0;i intersectingElems; @@ -171,6 +171,13 @@ void DataArray::reprWithoutNameStream(std::ostream& stream) const stream << "\n"; } +std::string DataArray::cppRepr(const char *varName) const throw(INTERP_KERNEL::Exception) +{ + std::ostringstream ret; + reprCppStream(varName,ret); + return ret.str(); +} + void DataArray::setInfoOnComponents(const std::vector& info) throw(INTERP_KERNEL::Exception) { if(getNumberOfComponents()!=(int)info.size()) @@ -720,6 +727,24 @@ void DataArrayDouble::reprZipWithoutNameStream(std::ostream& stream) const _mem.reprZip(getNumberOfComponents(),stream); } +void DataArrayDouble::reprCppStream(const char *varName, std::ostream& stream) const +{ + int nbTuples=getNumberOfTuples(),nbComp=getNumberOfComponents(); + const double *data=getConstPointer(); + stream.precision(17); + stream << "DataArrayDouble *" << varName << "=DataArrayDouble::New();" << std::endl; + if(nbTuples*nbComp>=1) + { + stream << "const double " << varName << "Data[" << nbTuples*nbComp << "]={"; + std::copy(data,data+nbTuples*nbComp-1,std::ostream_iterator(stream,",")); + stream << data[nbTuples*nbComp-1] << "};" << std::endl; + stream << varName << "->useArray(" << varName << "Data,false,CPP_DEALLOC," << nbTuples << "," << nbComp << ");" << std::endl; + } + else + stream << varName << "->alloc(" << nbTuples << "," << nbComp << ");" << std::endl; + stream << varName << "->setName(\"" << getName() << "\");" << std::endl; +} + bool DataArrayDouble::isEqualIfNotWhy(const DataArrayDouble& other, double prec, std::string& reason) const { if(!areInfoEqualsIfNotWhy(other,reason)) @@ -1739,19 +1764,19 @@ void DataArrayDouble::computeTupleIdsNearTuples(const DataArrayDouble *other, do case 3: { BBTree<3,int> myTree(bbox->getConstPointer(),0,0,getNumberOfTuples(),eps/10); - findTupleIdsNearTuplesAlg<3>(myTree,other->getConstPointer(),nbOfTuplesOther,eps,c,cI); + FindTupleIdsNearTuplesAlg<3>(myTree,other->getConstPointer(),nbOfTuplesOther,eps,c,cI); break; } case 2: { BBTree<2,int> myTree(bbox->getConstPointer(),0,0,getNumberOfTuples(),eps/10); - findTupleIdsNearTuplesAlg<2>(myTree,other->getConstPointer(),nbOfTuplesOther,eps,c,cI); + FindTupleIdsNearTuplesAlg<2>(myTree,other->getConstPointer(),nbOfTuplesOther,eps,c,cI); break; } case 1: { BBTree<1,int> myTree(bbox->getConstPointer(),0,0,getNumberOfTuples(),eps/10); - findTupleIdsNearTuplesAlg<1>(myTree,other->getConstPointer(),nbOfTuplesOther,eps,c,cI); + FindTupleIdsNearTuplesAlg<1>(myTree,other->getConstPointer(),nbOfTuplesOther,eps,c,cI); break; } default: @@ -3553,6 +3578,23 @@ void DataArrayInt::reprZipWithoutNameStream(std::ostream& stream) const _mem.reprZip(getNumberOfComponents(),stream); } +void DataArrayInt::reprCppStream(const char *varName, std::ostream& stream) const +{ + int nbTuples=getNumberOfTuples(),nbComp=getNumberOfComponents(); + const int *data=getConstPointer(); + stream << "DataArrayInt *" << varName << "=DataArrayInt::New();" << std::endl; + if(nbTuples*nbComp>=1) + { + stream << "const int " << varName << "Data[" << nbTuples*nbComp << "]={"; + std::copy(data,data+nbTuples*nbComp-1,std::ostream_iterator(stream,",")); + stream << data[nbTuples*nbComp-1] << "};" << std::endl; + stream << varName << "->useArray(" << varName << "Data,false,CPP_DEALLOC," << nbTuples << "," << nbComp << ");" << std::endl; + } + else + stream << varName << "->alloc(" << nbTuples << "," << nbComp << ");" << std::endl; + stream << varName << "->setName(\"" << getName() << "\");" << std::endl; +} + /*! * This method expects a number of components equal to 1. * This method sweeps all the values (tuples) in 'this' (it should be allocated) and for each value v is replaced by @@ -3891,7 +3933,7 @@ DataArrayInt *DataArrayInt::renumberR(const int *new2Old) const } /*! - * Idem DataArrayDouble::renumber method except that the number of tuples is reduced. + * Idem DataArrayInt::renumber method except that the number of tuples is reduced. * That is to say that it is expected that newNbOfTuplegetNumberOfTuples(). * ['old2New','old2New'+getNumberOfTuples()) defines a range containing old to new array. For every negative value in ['old2NewBg','old2New'getNumberOfTuples()) the corresponding tuple is * omitted. @@ -5468,6 +5510,30 @@ DataArrayInt *DataArrayInt::buildIntersection(const DataArrayInt *other) const t return BuildIntersection(arrs); } +/*! + * This method can be applied on allocated with one component DataArrayInt instance. + * This method is typically relevant for sorted arrays. All consecutive duplicated items in \a this will appear only once in returned DataArrayInt instance. + * Example : if \a this contains [1,2,2,3,3,3,3,4,5,5,7,7,7,19] the returned array will contain [1,2,3,4,5,7,19] + * + * \return a newly allocated array that contain the result of the unique operation applied on \a this. + * \throw if \a this is not allocated or if \a this has not exactly one component. + */ +DataArrayInt *DataArrayInt::buildUnique() const throw(INTERP_KERNEL::Exception) +{ + checkAllocated(); + if(getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayInt::buildUnique : only single component allowed !"); + int nbOfTuples=getNumberOfTuples(); + MEDCouplingAutoRefCountObjectPtr tmp=deepCpy(); + int *data=tmp->getPointer(); + int *last=std::unique(data,data+nbOfTuples); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); + ret->alloc(std::distance(data,last),1); + std::copy(data,last,ret->getPointer()); + ret->incrRef(); + return ret; +} + /*! * This method could be usefull for returned DataArrayInt marked as index. Some methods that generate such DataArrayInt instances: * - ParaMEDMEM::MEDCouplingUMesh::buildDescendingConnectivity @@ -5729,13 +5795,50 @@ DataArrayInt *DataArrayInt::duplicateEachTupleNTimes(int nbTimes) const throw(IN } /*! - * This method returns all different values found in 'this'. + * This method returns all different values found in \a this. This method throws if \a this has not been allocated. + * But the number of components can be different from one. */ std::set DataArrayInt::getDifferentValues() const throw(INTERP_KERNEL::Exception) { checkAllocated(); std::set ret; - ret.insert(getConstPointer(),getConstPointer()+getNbOfElems()); + ret.insert(begin(),end()); + return ret; +} + +/*! + * This method is a refinement of DataArrayInt::getDifferentValues because it returns not only different values in \a this but also, for each of + * them it tells which tuple id have this id. + * This method works only on arrays with one component (if it is not the case call DataArrayInt::rearrange(1) ). + * This method returns two arrays having same size. + * The instances of DataArrayInt in the returned vector have be specially allocated and computed by this method. Each of them should be dealt by the caller of this method. + * Example : if this is equal to [1,0,1,2,0,2,2,-3,2] -> differentIds=[-3,0,1,2] and returned array will be equal to [[7],[1,4],[0,2],[3,5,6,8]] + */ +std::vector DataArrayInt::partitionByDifferentValues(std::vector& differentIds) const throw(INTERP_KERNEL::Exception) +{ + checkAllocated(); + if(getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayInt::partitionByDifferentValues : this should have only one component !"); + int id=0; + std::map m,m2,m3; + for(const int *w=begin();w!=end();w++) + m[*w]++; + differentIds.resize(m.size()); + std::vector ret(m.size()); + std::vector retPtr(m.size()); + for(std::map::const_iterator it=m.begin();it!=m.end();it++,id++) + { + m2[(*it).first]=id; + ret[id]=DataArrayInt::New(); + ret[id]->alloc((*it).second,1); + retPtr[id]=ret[id]->getPointer(); + differentIds[id]=(*it).first; + } + id=0; + for(const int *w=begin();w!=end();w++,id++) + { + retPtr[m2[*w]][m3[*w]++]=id; + } return ret; } diff --git a/src/MEDCoupling/MEDCouplingMemArray.hxx b/src/MEDCoupling/MEDCouplingMemArray.hxx index 675a563ec..6b8b5853f 100644 --- a/src/MEDCoupling/MEDCouplingMemArray.hxx +++ b/src/MEDCoupling/MEDCouplingMemArray.hxx @@ -98,6 +98,7 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT bool areInfoEqualsIfNotWhy(const DataArray& other, std::string& reason) const; MEDCOUPLING_EXPORT bool areInfoEquals(const DataArray& other) const; MEDCOUPLING_EXPORT void reprWithoutNameStream(std::ostream& stream) const; + MEDCOUPLING_EXPORT std::string cppRepr(const char *varName) const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT std::string getName() const { return _name; } MEDCOUPLING_EXPORT const std::vector &getInfoOnComponents() const { return _info_on_compo; } MEDCOUPLING_EXPORT std::vector &getInfoOnComponents() { return _info_on_compo; } @@ -112,8 +113,7 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT int getNumberOfTuples() const { return _nb_of_tuples; } MEDCOUPLING_EXPORT int getNbOfElems() const { return ((int)_info_on_compo.size())*_nb_of_tuples; } MEDCOUPLING_EXPORT void checkNbOfTuples(int nbOfTuples, const char *msg) const throw(INTERP_KERNEL::Exception); - MEDCOUPLING_EXPORT -void checkNbOfComps(int nbOfCompo, const char *msg) const throw(INTERP_KERNEL::Exception); + MEDCOUPLING_EXPORT void checkNbOfComps(int nbOfCompo, const char *msg) const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT void checkNbOfTuplesAndComp(const DataArray& other, const char *msg) const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT void checkNbOfTuplesAndComp(int nbOfTuples, int nbOfCompo, const char *msg) const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT void checkNbOfElems(int nbOfElems, const char *msg) const throw(INTERP_KERNEL::Exception); @@ -122,6 +122,7 @@ void checkNbOfComps(int nbOfCompo, const char *msg) const throw(INTERP_KERNEL::E MEDCOUPLING_EXPORT static int GetPosOfItemGivenBESRelativeNoThrow(int value, int begin, int end, int step) throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT static std::string GetVarNameFromInfo(const std::string& info) throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT static std::string GetUnitFromInfo(const std::string& info) throw(INTERP_KERNEL::Exception); + MEDCOUPLING_EXPORT virtual void reprCppStream(const char *varName, std::ostream& stream) const = 0; protected: DataArray():_nb_of_tuples(-1) { } protected: @@ -170,6 +171,7 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT void reprZipStream(std::ostream& stream) const; MEDCOUPLING_EXPORT void reprWithoutNameStream(std::ostream& stream) const; MEDCOUPLING_EXPORT void reprZipWithoutNameStream(std::ostream& stream) const; + MEDCOUPLING_EXPORT void reprCppStream(const char *varName, std::ostream& stream) const; MEDCOUPLING_EXPORT bool isEqual(const DataArrayDouble& other, double prec) const; MEDCOUPLING_EXPORT bool isEqualIfNotWhy(const DataArrayDouble& other, double prec, std::string& reason) const; MEDCOUPLING_EXPORT bool isEqualWithoutConsideringStr(const DataArrayDouble& other, double prec) const; @@ -292,8 +294,8 @@ namespace ParaMEDMEM template void findCommonTuplesAlg(const double *bbox, int nbNodes, int limitNodeId, double prec, std::vector& c, std::vector& cI) const; template - void findTupleIdsNearTuplesAlg(const BBTree& myTree, const double *pos, int nbOfTuples, double eps, - std::vector& c, std::vector& cI) const; + static void FindTupleIdsNearTuplesAlg(const BBTree& myTree, const double *pos, int nbOfTuples, double eps, + std::vector& c, std::vector& cI); private: DataArrayDouble() { } private: @@ -365,6 +367,7 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT void reprZipStream(std::ostream& stream) const; MEDCOUPLING_EXPORT void reprWithoutNameStream(std::ostream& stream) const; MEDCOUPLING_EXPORT void reprZipWithoutNameStream(std::ostream& stream) const; + MEDCOUPLING_EXPORT void reprCppStream(const char *varName, std::ostream& stream) const; MEDCOUPLING_EXPORT void transformWithIndArr(const int *indArrBg, const int *indArrEnd) throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT DataArrayInt *transformWithIndArrR(const int *indArrBg, const int *indArrEnd) const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT void splitByValueRange(const int *arrBg, const int *arrEnd, @@ -455,6 +458,7 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT DataArrayInt *buildSubstraction(const DataArrayInt *other) const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT DataArrayInt *buildUnion(const DataArrayInt *other) const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT DataArrayInt *buildIntersection(const DataArrayInt *other) const throw(INTERP_KERNEL::Exception); + MEDCOUPLING_EXPORT DataArrayInt *buildUnique() const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT DataArrayInt *deltaShiftIndex() const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT void computeOffsets() throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT void computeOffsets2() throw(INTERP_KERNEL::Exception); @@ -463,6 +467,7 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT DataArrayInt *findIdInRangeForEachTuple(const DataArrayInt *ranges) const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT DataArrayInt *duplicateEachTupleNTimes(int nbTimes) const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT std::set getDifferentValues() const throw(INTERP_KERNEL::Exception); + MEDCOUPLING_EXPORT std::vector partitionByDifferentValues(std::vector& differentIds) const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT void useArray(const int *array, bool ownership, DeallocType type, int nbOfTuple, int nbOfCompo); MEDCOUPLING_EXPORT void useExternalArrayWithRWAccess(const int *array, int nbOfTuple, int nbOfCompo); MEDCOUPLING_EXPORT void writeOnPlace(int id, int element0, const int *others, int sizeOfOthers) { _mem.writeOnPlace(id,element0,others,sizeOfOthers); } diff --git a/src/MEDCoupling/MEDCouplingMesh.cxx b/src/MEDCoupling/MEDCouplingMesh.cxx index d226fd90d..e0a9c7883 100644 --- a/src/MEDCoupling/MEDCouplingMesh.cxx +++ b/src/MEDCoupling/MEDCouplingMesh.cxx @@ -392,6 +392,18 @@ int MEDCouplingMesh::GetDimensionOfGeometricType(INTERP_KERNEL::NormalizedCellTy return (int) cm.getDimension(); } +/*! + * \param [in] type the geometric type for which the representation is asked. + * \return the string representation corresponding to the input geometric type \a type. + * + * \throw if type is equal to \c INTERP_KERNEL::NORM_ERROR or to an unexisting geometric type. + */ +const char *MEDCouplingMesh::GetReprOfGeometricType(INTERP_KERNEL::NormalizedCellType type) throw(INTERP_KERNEL::Exception) +{ + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type); + return cm.getRepr(); +} + void MEDCouplingMesh::getCellsContainingPoint(const double *pos, double eps, std::vector& elts) const { int ret=getCellContainingPoint(pos,eps); diff --git a/src/MEDCoupling/MEDCouplingMesh.hxx b/src/MEDCoupling/MEDCouplingMesh.hxx index 988ab77e9..2febf8c6b 100644 --- a/src/MEDCoupling/MEDCouplingMesh.hxx +++ b/src/MEDCoupling/MEDCouplingMesh.hxx @@ -118,6 +118,7 @@ namespace ParaMEDMEM static MEDCouplingMesh *MergeMeshes(const MEDCouplingMesh *mesh1, const MEDCouplingMesh *mesh2) throw(INTERP_KERNEL::Exception); static MEDCouplingMesh *MergeMeshes(std::vector& meshes) throw(INTERP_KERNEL::Exception); static int GetDimensionOfGeometricType(INTERP_KERNEL::NormalizedCellType type) throw(INTERP_KERNEL::Exception); + static const char *GetReprOfGeometricType(INTERP_KERNEL::NormalizedCellType type) throw(INTERP_KERNEL::Exception); //serialisation-unserialization virtual void getTinySerializationInformation(std::vector& tinyInfoD, std::vector& tinyInfo, std::vector& littleStrings) const = 0; virtual void resizeForUnserialization(const std::vector& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector& littleStrings) const = 0; diff --git a/src/MEDCoupling/MEDCouplingRemapper.cxx b/src/MEDCoupling/MEDCouplingRemapper.cxx index 0ef48eec7..8a489b139 100644 --- a/src/MEDCoupling/MEDCouplingRemapper.cxx +++ b/src/MEDCoupling/MEDCouplingRemapper.cxx @@ -24,7 +24,9 @@ #include "MEDCouplingFieldTemplate.hxx" #include "MEDCouplingFieldDiscretization.hxx" #include "MEDCouplingExtrudedMesh.hxx" +#include "MEDCouplingCMesh.hxx" #include "MEDCouplingNormalizedUnstructuredMesh.txx" +#include "MEDCouplingNormalizedCartesianMesh.txx" #include "Interpolation1D.txx" #include "Interpolation2DCurve.hxx" @@ -33,6 +35,8 @@ #include "Interpolation3DSurf.hxx" #include "Interpolation2D1D.txx" #include "Interpolation3D2D.txx" +#include "InterpolationCU.txx" +#include "InterpolationCC.txx" using namespace ParaMEDMEM; @@ -55,6 +59,12 @@ int MEDCouplingRemapper::prepare(const MEDCouplingMesh *srcMesh, const MEDCoupli { case 85://Unstructured-Unstructured return prepareUU(method); + case 87://Unstructured-Cartesian + return prepareUC(method); + case 117://Cartesian-Unstructured + return prepareCU(method); + case 119://Cartesian-Cartesian + return prepareCC(method); case 136://Extruded-Extruded return prepareEE(method); default: @@ -232,7 +242,7 @@ int MEDCouplingRemapper::prepareUU(const char *method) throw(INTERP_KERNEL::Exce INTERP_KERNEL::Interpolation3D interpolation(*this); std::vector > matrixTmp; nbCols=interpolation.interpolateMeshes(target_mesh_wrapper,source_mesh_wrapper,matrixTmp,method); - reverseMatrix(matrixTmp,nbCols,_matrix); + ReverseMatrix(matrixTmp,nbCols,_matrix); nbCols=matrixTmp.size(); } else if(srcMeshDim==2 && trgMeshDim==1 && srcSpaceDim==2) @@ -251,7 +261,7 @@ int MEDCouplingRemapper::prepareUU(const char *method) throw(INTERP_KERNEL::Exce INTERP_KERNEL::Interpolation2D1D interpolation(*this); std::vector > matrixTmp; nbCols=interpolation.interpolateMeshes(target_mesh_wrapper,source_mesh_wrapper,matrixTmp,method); - reverseMatrix(matrixTmp,nbCols,_matrix); + ReverseMatrix(matrixTmp,nbCols,_matrix); nbCols=matrixTmp.size(); INTERP_KERNEL::Interpolation2D1D::DuplicateFacesType duplicateFaces=interpolation.retrieveDuplicateFaces(); if(!duplicateFaces.empty()) @@ -275,7 +285,7 @@ int MEDCouplingRemapper::prepareUU(const char *method) throw(INTERP_KERNEL::Exce INTERP_KERNEL::Interpolation2D interpolation(*this); std::vector > matrixTmp; nbCols=interpolation.interpolateMeshes(target_mesh_wrapper,source_mesh_wrapper,matrixTmp,method); - reverseMatrix(matrixTmp,nbCols,_matrix); + ReverseMatrix(matrixTmp,nbCols,_matrix); nbCols=matrixTmp.size(); } else @@ -322,7 +332,7 @@ int MEDCouplingRemapper::prepareUU(const char *method) throw(INTERP_KERNEL::Exce INTERP_KERNEL::Interpolation3D2D interpolation(*this); std::vector > matrixTmp; nbCols=interpolation.interpolateMeshes(target_mesh_wrapper,source_mesh_wrapper,matrixTmp,method); - reverseMatrix(matrixTmp,nbCols,_matrix); + ReverseMatrix(matrixTmp,nbCols,_matrix); nbCols=matrixTmp.size(); INTERP_KERNEL::Interpolation3D2D::DuplicateFacesType duplicateFaces=interpolation.retrieveDuplicateFaces(); if(!duplicateFaces.empty()) @@ -426,6 +436,163 @@ int MEDCouplingRemapper::prepareEE(const char *method) throw(INTERP_KERNEL::Exce return 1; } +int MEDCouplingRemapper::prepareUC(const char *method) throw(INTERP_KERNEL::Exception) +{ + std::string methodCpp(method); + if(methodCpp!="P0P0") + throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareUC : only P0P0 interpolation supported for the moment !"); + INTERP_KERNEL::Interpolation::checkAndSplitInterpolationMethod(method,_src_method,_target_method); + MEDCouplingUMesh *src_mesh=static_cast(_src_mesh); + MEDCouplingCMesh *target_mesh=static_cast(_target_mesh); + const int srcMeshDim=src_mesh->getMeshDimension(); + const int srcSpceDim=src_mesh->getSpaceDimension(); + const int trgMeshDim=target_mesh->getMeshDimension(); + if(srcMeshDim!=srcSpceDim || srcMeshDim!=trgMeshDim) + throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareUC : space dim of src unstructured should be equal to mesh dim of src unstructured and should be equal also equal to trg cartesian dimension !"); + std::vector > res; + switch(srcMeshDim) + { + case 1: + { + MEDCouplingNormalizedCartesianMesh<1> targetWrapper(target_mesh); + MEDCouplingNormalizedUnstructuredMesh<1,1> sourceWrapper(src_mesh); + INTERP_KERNEL::InterpolationCU myInterpolator(*this); + myInterpolator.interpolateMeshes(targetWrapper,sourceWrapper,res,"P0P0"); + break; + } + case 2: + { + MEDCouplingNormalizedCartesianMesh<2> targetWrapper(target_mesh); + MEDCouplingNormalizedUnstructuredMesh<2,2> sourceWrapper(src_mesh); + INTERP_KERNEL::InterpolationCU myInterpolator(*this); + myInterpolator.interpolateMeshes(targetWrapper,sourceWrapper,res,"P0P0"); + break; + } + case 3: + { + MEDCouplingNormalizedCartesianMesh<3> targetWrapper(target_mesh); + MEDCouplingNormalizedUnstructuredMesh<3,3> sourceWrapper(src_mesh); + INTERP_KERNEL::InterpolationCU myInterpolator(*this); + myInterpolator.interpolateMeshes(targetWrapper,sourceWrapper,res,"P0P0"); + break; + } + default: + throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareUC : only dimension 1 2 or 3 supported !"); + } + ReverseMatrix(res,target_mesh->getNumberOfCells(),_matrix); + nullifiedTinyCoeffInCrudeMatrixAbs(0.); + // + _deno_multiply.clear(); + _deno_multiply.resize(_matrix.size()); + _deno_reverse_multiply.clear(); + _deno_reverse_multiply.resize(src_mesh->getNumberOfCells()); + declareAsNew(); + return 1; +} + +int MEDCouplingRemapper::prepareCU(const char *method) throw(INTERP_KERNEL::Exception) +{ + std::string methodCpp(method); + if(methodCpp!="P0P0") + throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCU : only P0P0 interpolation supported for the moment !"); + INTERP_KERNEL::Interpolation::checkAndSplitInterpolationMethod(method,_src_method,_target_method); + MEDCouplingCMesh *src_mesh=static_cast(_src_mesh); + MEDCouplingUMesh *target_mesh=static_cast(_target_mesh); + const int srcMeshDim=src_mesh->getMeshDimension(); + const int trgMeshDim=target_mesh->getMeshDimension(); + const int trgSpceDim=target_mesh->getSpaceDimension(); + if(trgMeshDim!=trgSpceDim || trgMeshDim!=srcMeshDim) + throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCU : space dim of target unstructured should be equal to mesh dim of target unstructured and should be equal also equal to source cartesian dimension !"); + switch(srcMeshDim) + { + case 1: + { + MEDCouplingNormalizedCartesianMesh<1> sourceWrapper(src_mesh); + MEDCouplingNormalizedUnstructuredMesh<1,1> targetWrapper(target_mesh); + INTERP_KERNEL::InterpolationCU myInterpolator(*this); + myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0"); + break; + } + case 2: + { + MEDCouplingNormalizedCartesianMesh<2> sourceWrapper(src_mesh); + MEDCouplingNormalizedUnstructuredMesh<2,2> targetWrapper(target_mesh); + INTERP_KERNEL::InterpolationCU myInterpolator(*this); + myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0"); + break; + } + case 3: + { + MEDCouplingNormalizedCartesianMesh<3> sourceWrapper(src_mesh); + MEDCouplingNormalizedUnstructuredMesh<3,3> targetWrapper(target_mesh); + INTERP_KERNEL::InterpolationCU myInterpolator(*this); + myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0"); + break; + } + default: + throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCU : only dimension 1 2 or 3 supported !"); + } + nullifiedTinyCoeffInCrudeMatrixAbs(0.); + // + _deno_multiply.clear(); + _deno_multiply.resize(_matrix.size()); + _deno_reverse_multiply.clear(); + _deno_reverse_multiply.resize(src_mesh->getNumberOfCells()); + declareAsNew(); + return 1; +} + +int MEDCouplingRemapper::prepareCC(const char *method) throw(INTERP_KERNEL::Exception) +{ + std::string methodCpp(method); + if(methodCpp!="P0P0") + throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCC : only P0P0 interpolation supported for the moment !"); + INTERP_KERNEL::Interpolation::checkAndSplitInterpolationMethod(method,_src_method,_target_method); + MEDCouplingCMesh *src_mesh=static_cast(_src_mesh); + MEDCouplingCMesh *target_mesh=static_cast(_target_mesh); + const int srcMeshDim=src_mesh->getMeshDimension(); + const int trgMeshDim=target_mesh->getMeshDimension(); + if(trgMeshDim!=srcMeshDim) + throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCC : dim of target cartesian should be equal to dim of source cartesian dimension !"); + switch(srcMeshDim) + { + case 1: + { + MEDCouplingNormalizedCartesianMesh<1> sourceWrapper(src_mesh); + MEDCouplingNormalizedCartesianMesh<1> targetWrapper(target_mesh); + INTERP_KERNEL::InterpolationCC myInterpolator(*this); + myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0"); + break; + } + case 2: + { + MEDCouplingNormalizedCartesianMesh<2> sourceWrapper(src_mesh); + MEDCouplingNormalizedCartesianMesh<2> targetWrapper(target_mesh); + INTERP_KERNEL::InterpolationCC myInterpolator(*this); + myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0"); + break; + } + case 3: + { + MEDCouplingNormalizedCartesianMesh<3> sourceWrapper(src_mesh); + MEDCouplingNormalizedCartesianMesh<3> targetWrapper(target_mesh); + INTERP_KERNEL::InterpolationCC myInterpolator(*this); + myInterpolator.interpolateMeshes(sourceWrapper,targetWrapper,_matrix,"P0P0"); + break; + } + default: + throw INTERP_KERNEL::Exception("MEDCouplingRemapper::prepareCC : only dimension 1 2 or 3 supported !"); + } + nullifiedTinyCoeffInCrudeMatrixAbs(0.); + // + _deno_multiply.clear(); + _deno_multiply.resize(_matrix.size()); + _deno_reverse_multiply.clear(); + _deno_reverse_multiply.resize(src_mesh->getNumberOfCells()); + declareAsNew(); + return 1; +} + void MEDCouplingRemapper::updateTime() const { } @@ -494,7 +661,7 @@ void MEDCouplingRemapper::computeDenoFromScratch(NatureOfField nat, const MEDCou { case ConservativeVolumic: { - computeRowSumAndColSum(_matrix,_deno_multiply,_deno_reverse_multiply); + ComputeRowSumAndColSum(_matrix,_deno_multiply,_deno_reverse_multiply); break; } case Integral: @@ -526,7 +693,7 @@ void MEDCouplingRemapper::computeDenoFromScratch(NatureOfField nat, const MEDCou } case IntegralGlobConstraint: { - computeColSumAndRowSum(_matrix,_deno_multiply,_deno_reverse_multiply); + ComputeColSumAndRowSum(_matrix,_deno_multiply,_deno_reverse_multiply); break; } case RevIntegral: @@ -607,7 +774,7 @@ void MEDCouplingRemapper::computeReverseProduct(const double *inputPointer, int std::fill(resPointer+idx*inputNbOfCompo,resPointer+(idx+1)*inputNbOfCompo,dftValue); } -void MEDCouplingRemapper::reverseMatrix(const std::vector >& matIn, int nbColsMatIn, std::vector >& matOut) +void MEDCouplingRemapper::ReverseMatrix(const std::vector >& matIn, int nbColsMatIn, std::vector >& matOut) { matOut.resize(nbColsMatIn); int id=0; @@ -616,7 +783,7 @@ void MEDCouplingRemapper::reverseMatrix(const std::vector > matOut[(*iter2).first][id]=(*iter2).second; } -void MEDCouplingRemapper::computeRowSumAndColSum(const std::vector >& matrixDeno, +void MEDCouplingRemapper::ComputeRowSumAndColSum(const std::vector >& matrixDeno, std::vector >& deno, std::vector >& denoReverse) { std::map values; @@ -640,7 +807,7 @@ void MEDCouplingRemapper::computeRowSumAndColSum(const std::vector >& matrixDeno, +void MEDCouplingRemapper::ComputeColSumAndRowSum(const std::vector >& matrixDeno, std::vector >& deno, std::vector >& denoReverse) { std::map values; diff --git a/src/MEDCoupling/MEDCouplingRemapper.hxx b/src/MEDCoupling/MEDCouplingRemapper.hxx index c2005df8e..41948c2fb 100644 --- a/src/MEDCoupling/MEDCouplingRemapper.hxx +++ b/src/MEDCoupling/MEDCouplingRemapper.hxx @@ -65,6 +65,9 @@ namespace ParaMEDMEM private: int prepareUU(const char *method) throw(INTERP_KERNEL::Exception); int prepareEE(const char *method) throw(INTERP_KERNEL::Exception); + int prepareUC(const char *method) throw(INTERP_KERNEL::Exception); + int prepareCU(const char *method) throw(INTERP_KERNEL::Exception); + int prepareCC(const char *method) throw(INTERP_KERNEL::Exception); void updateTime() const; void releaseData(bool matrixSuppression); void transferUnderground(const MEDCouplingFieldDouble *srcField, MEDCouplingFieldDouble *targetField, bool isDftVal, double dftValue) throw(INTERP_KERNEL::Exception); @@ -76,11 +79,11 @@ namespace ParaMEDMEM const std::vector< std::map >& m2D, const int *corrCellIdSrc, int nbOf2DCellsSrc, int nbOf1DCellsSrc, const int *corrCellIdTrg); - static void reverseMatrix(const std::vector >& matIn, int nbColsMatIn, + static void ReverseMatrix(const std::vector >& matIn, int nbColsMatIn, std::vector >& matOut); - static void computeRowSumAndColSum(const std::vector >& matrixDeno, + static void ComputeRowSumAndColSum(const std::vector >& matrixDeno, std::vector >& deno, std::vector >& denoReverse); - static void computeColSumAndRowSum(const std::vector >& matrixDeno, + static void ComputeColSumAndRowSum(const std::vector >& matrixDeno, std::vector >& deno, std::vector >& denoReverse); private: MEDCouplingMesh *_src_mesh; diff --git a/src/MEDCoupling/MEDCouplingUMesh.cxx b/src/MEDCoupling/MEDCouplingUMesh.cxx index e5c84bfc6..dae38283f 100644 --- a/src/MEDCoupling/MEDCouplingUMesh.cxx +++ b/src/MEDCoupling/MEDCouplingUMesh.cxx @@ -1062,7 +1062,6 @@ void MEDCouplingUMesh::simplifyPolyhedra(double eps) throw(INTERP_KERNEL::Except throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !"); MEDCouplingAutoRefCountObjectPtr coords=getCoords()->deepCpy(); coords->recenterForMaxPrecision(eps); - const double *coordsPtr=coords->getConstPointer(); // int nbOfCells=getNumberOfCells(); const int *conn=_nodal_connec->getConstPointer(); @@ -1612,7 +1611,6 @@ bool MEDCouplingUMesh::areCellsIncludedIn2(const MEDCouplingUMesh *other, DataAr } int thisNbCells=getNumberOfCells(); int otherNbCells=other->getNumberOfCells(); - int nbOfCells=mesh->getNumberOfCells(); MEDCouplingAutoRefCountObjectPtr arr2=DataArrayInt::New(); arr2->alloc(otherNbCells,1); arr2->fillWithZero(); @@ -1794,9 +1792,7 @@ void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsE } int nbOfCells=getNumberOfCells(); bool easyAssign=true; - const int *conn=_nodal_connec->getConstPointer(); const int *connI=_nodal_connec_index->getConstPointer(); - const int *connOther=otherOnSameCoordsThanThis._nodal_connec->getConstPointer(); const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer(); for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++) { @@ -1845,9 +1841,7 @@ void MEDCouplingUMesh::setPartOfMySelf2(int start, int end, int step, const MEDC } int nbOfCells=getNumberOfCells(); bool easyAssign=true; - const int *conn=_nodal_connec->getConstPointer(); const int *connI=_nodal_connec_index->getConstPointer(); - const int *connOther=otherOnSameCoordsThanThis._nodal_connec->getConstPointer(); const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer(); int it=start; for(int i=0;igetConstPointer(); const int *pt=_nodal_connec->getConstPointer(); - return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]]; + if(cellId>=0 && cellId<_nodal_connec_index->getNbOfElems()-1) + return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]]; + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } } /*! @@ -2604,6 +2604,27 @@ std::string MEDCouplingUMesh::advancedRepr() const return ret.str(); } +/*! + * This method returns a C++ code that is a dump of \a this. + * This method will throw if this is not fully defined. + */ +std::string MEDCouplingUMesh::cppRepr() const throw(INTERP_KERNEL::Exception) +{ + static const char coordsName[]="coords"; + static const char connName[]="conn"; + static const char connIName[]="connI"; + checkFullyDefined(); + std::ostringstream ret; ret << "// coordinates" << std::endl; + _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl; + _nodal_connec->reprCppStream(connName,ret); ret << std::endl; + _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl; + ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl; + ret << "mesh->setCoords(" << coordsName << ");" << std::endl; + ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl; + ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl; + return ret.str(); +} + std::string MEDCouplingUMesh::reprConnectivityOfThis() const { std::ostringstream ret; @@ -3341,10 +3362,10 @@ MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const { checkFullyDefined(); if(getMeshDimension()!=2 || getSpaceDimension()!=3) - throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !"); + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !"); MEDCouplingAutoRefCountObjectPtr candidates=getCellIdsCrossingPlane(origin,vec,eps); if(candidates->empty()) - throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !"); + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !"); std::vector nodes; std::vector cellIds1D; MEDCouplingAutoRefCountObjectPtr subMesh=static_cast(buildPartOfMySelf(candidates->begin(),candidates->end(),false)); @@ -5220,10 +5241,17 @@ DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector< } /*! - * This method makes the hypothesis that 'this' is sorted by type. If not an exception will be thrown. - * This method is the opposite of MEDCouplingUMesh::checkTypeConsistencyAndContig method. Given a list of cells in 'profile' it returns a list of profiles sorted by geo type. - * This method has 1 input 'profile' and 2 outputs 'code' and 'idsPerType'. - * @throw if 'profile' has not exactly one component. It throws too, if 'profile' contains some values not in [0,getNumberOfCells()) or if 'this' is not fully defined + * This method makes the hypothesis that \at this is sorted by type. If not an exception will be thrown. + * This method is the opposite of MEDCouplingUMesh::checkTypeConsistencyAndContig method. Given a list of cells in \a profile it returns a list of sub-profiles sorted by geo type. + * The result is put in the array \a idsPerType. In the returned parameter \a code, foreach i \a code[3*i+2] refers (if different from -1) to a location into the \a idsPerType. + * This method has 1 input \a profile and 3 outputs \a code' \a idsInPflPerType and \a idsPerType. + * + * @param [out] code is a vector of size 3*n where n is the number of different geometric type in \a this \b reduced to the profile \a profile. \a code has exactly the same semantic than in MEDCouplingUMesh::checkTypeConsistencyAndContig method. + * @param [out] idsInPflPerType is a vector of size of different geometric type in the subpart defined by \a profile of \a this ( equal to \a code.size()/3). For each i, + * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0] + * @param [out] idsPerType is a vector of size of different sub profiles needed to be defined to represent the profile \a profile for a given geometric type. + * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile. + * @throw if \a profile has not exactly one component. It throws too, if \a profile contains some values not in [0,getNumberOfCells()) or if 'this' is not fully defined */ void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector& code, std::vector& idsInPflPerType, std::vector& idsPerType) const throw(INTERP_KERNEL::Exception) { @@ -5641,32 +5669,45 @@ DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *d /*! * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type' + * This method \b works \b for mesh sorted by type. * cells whose ids is in 'idsPerGeoType' array. * This method conserves coords and name of mesh. */ MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const { - std::vector idsTokeep; - int nbOfCells=getNumberOfCells(); - int j=0; - for(int i=0;i code=getDistributionOfTypes(); + std::size_t nOfTypesInThis=code.size()/3; + int sz=0,szOfType=0; + for(std::size_t i=0;i=szOfType) { - if(std::find(idsPerGeoTypeBg,idsPerGeoTypeEnd,j)!=idsPerGeoTypeEnd) - idsTokeep.push_back(i); - j++; + std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work; + oss << ". It should be in [0," << szOfType << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); } - MEDCouplingPointSet *ret=buildPartOfMySelf(&idsTokeep[0],&idsTokeep[0]+idsTokeep.size(),true); - MEDCouplingUMesh *ret2=dynamic_cast(ret); - if(!ret2) + MEDCouplingAutoRefCountObjectPtr idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1); + int *idsPtr=idsTokeep->getPointer(); + int offset=0; + for(std::size_t i=0;idecrRef(); - return 0; + if(code[3*i]!=type) + for(int j=0;j(),offset)); + offset+=code[3*i+1]; } - ret2->copyTinyInfoFrom(this); - return ret2; + MEDCouplingAutoRefCountObjectPtr ret=static_cast(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true)); + ret->copyTinyInfoFrom(this); + ret->incrRef(); + return ret; } /*! @@ -6570,7 +6611,7 @@ void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData MEDCouplingAutoRefCountObjectPtr connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1); int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer(); int szFaceOffsets=0,szConn=0; - for(int i=0;iwriteVTK(ofs,8,"Int32","faces"); @@ -6714,6 +6755,7 @@ void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCo for(it1.first();!it1.finished();it1.next()) edges1.insert(it1.current()->getPtr()); // + std::map > edgesIn2ForShare; std::vector pol2s(candidates2.size()); int ii=0; for(std::vector::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++) @@ -6722,20 +6764,22 @@ void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCo const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2); MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev); pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2, - pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2); + pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2,edgesIn2ForShare); } ii=0; for(std::vector::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++) { - pol1.initLocations(); + pol1.initLocationsWithOther(pol2s[ii]); pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2); //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2); pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2); } + if(!edges1.empty()) + { + INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2); + } for(std::map::const_iterator it=mappRev.begin();it!=mappRev.end();it++) (*it).second->decrRef(); - //if(!edges1.empty()) - // std::cerr << "Cell #" << i << " in mesh m1 not fully overlapped !" << std::endl; } } @@ -7104,6 +7148,8 @@ bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, co return true; } } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !"); } else throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !"); @@ -7509,7 +7555,6 @@ MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const throw(INTER int spaceDim=getSpaceDimension(); if(mdim!=spaceDim) throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !"); - int nbCells=getNumberOfCells(); std::vector partition=partitionBySpreadZone(); std::vector< MEDCouplingAutoRefCountObjectPtr > partitionAuto; partitionAuto.reserve(partition.size()); std::copy(partition.begin(),partition.end(),std::back_insert_iterator > >(partitionAuto)); diff --git a/src/MEDCoupling/MEDCouplingUMesh.hxx b/src/MEDCoupling/MEDCouplingUMesh.hxx index eb28c5a30..7da64ee50 100644 --- a/src/MEDCoupling/MEDCouplingUMesh.hxx +++ b/src/MEDCoupling/MEDCouplingUMesh.hxx @@ -74,6 +74,7 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT DataArrayInt *getCellIdsFullyIncludedInNodeIds(const int *partBg, const int *partEnd) const; MEDCOUPLING_EXPORT std::string simpleRepr() const; MEDCOUPLING_EXPORT std::string advancedRepr() const; + MEDCOUPLING_EXPORT std::string cppRepr() const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT std::string reprConnectivityOfThis() const; MEDCOUPLING_EXPORT MEDCouplingUMesh *buildSetInstanceFromThis(int spaceDim) const throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT int getNumberOfNodesInCell(int cellId) const; diff --git a/src/MEDCoupling/Test/MEDCouplingBasicsTest1.cxx b/src/MEDCoupling/Test/MEDCouplingBasicsTest1.cxx index b1b83ca9e..9a55bea57 100644 --- a/src/MEDCoupling/Test/MEDCouplingBasicsTest1.cxx +++ b/src/MEDCoupling/Test/MEDCouplingBasicsTest1.cxx @@ -106,7 +106,7 @@ void MEDCouplingBasicsTest1::testArray3() DataArrayDouble *arr4=DataArrayDouble::New(); arr4->alloc(7,2); double *tmp2=arr4->getPointer(); - const int arr4Ref[14]={0.8,10.8,1.9,11.9,2.1,12.1,3.2,13.2,4.3,14.3,5.4,15.4,6.5,16.5}; + const double arr4Ref[14]={0.8,10.8,1.9,11.9,2.1,12.1,3.2,13.2,4.3,14.3,5.4,15.4,6.5,16.5}; std::copy(arr4Ref,arr4Ref+14,tmp2); CPPUNIT_ASSERT_EQUAL(7,arr4->getNumberOfTuples()); CPPUNIT_ASSERT_EQUAL(2,arr4->getNumberOfComponents()); diff --git a/src/MEDCoupling/Test/MEDCouplingBasicsTest2.cxx b/src/MEDCoupling/Test/MEDCouplingBasicsTest2.cxx index 89cf9818f..f6953bbd8 100644 --- a/src/MEDCoupling/Test/MEDCouplingBasicsTest2.cxx +++ b/src/MEDCoupling/Test/MEDCouplingBasicsTest2.cxx @@ -53,6 +53,7 @@ void MEDCouplingBasicsTest2::testGaussPointField1() CPPUNIT_ASSERT_EQUAL(5,f->getNumberOfMeshPlacesExpected()); CPPUNIT_ASSERT_EQUAL(0,f->getNbOfGaussLocalization()); f->setGaussLocalizationOnType(INTERP_KERNEL::NORM_TRI3,_refCoo1,_gsCoo1,_wg1); + f->setGaussLocalizationOnType(INTERP_KERNEL::NORM_TRI3,_refCoo1,_gsCoo1,_wg1); // not a bug only to check that it works well CPPUNIT_ASSERT_THROW(f->setGaussLocalizationOnType(INTERP_KERNEL::NORM_QUAD4,_refCoo1,_gsCoo1,_wg1),INTERP_KERNEL::Exception); CPPUNIT_ASSERT_EQUAL(1,f->getNbOfGaussLocalization()); const double refCoo2[8]={ 0.,0., 1.,0., 1.,1., 0.,1. }; diff --git a/src/MEDCoupling/Test/MEDCouplingBasicsTest3.cxx b/src/MEDCoupling/Test/MEDCouplingBasicsTest3.cxx index ce2fc84ec..fcc86c4ac 100644 --- a/src/MEDCoupling/Test/MEDCouplingBasicsTest3.cxx +++ b/src/MEDCoupling/Test/MEDCouplingBasicsTest3.cxx @@ -1388,9 +1388,9 @@ void MEDCouplingBasicsTest3::testExtrudedMesh5() DataArrayDouble *d=DataArrayDouble::New(); d->alloc(13,1); d->iota(); - MEDCouplingCMesh *e=MEDCouplingCMesh::New(); - e->setCoordsAt(0,d); - MEDCouplingUMesh *f=e->buildUnstructured(); + MEDCouplingCMesh *ee=MEDCouplingCMesh::New(); + ee->setCoordsAt(0,d); + MEDCouplingUMesh *f=ee->buildUnstructured(); DataArrayDouble *g=f->getCoords()->applyFunc(2,"3.5*IVec+x/6*3.14159265359*JVec"); CPPUNIT_ASSERT_THROW(f->getCoords()->applyFunc(2,"3.5*IVec+x/6*3.14159265359*KVec"),INTERP_KERNEL::Exception); // KVec refers to component #2 and there is only 2 components ! DataArrayDouble *h=g->fromPolarToCart(); @@ -1425,7 +1425,7 @@ void MEDCouplingBasicsTest3::testExtrudedMesh5() h->decrRef(); g->decrRef(); f->decrRef(); - e->decrRef(); + ee->decrRef(); d->decrRef(); c->decrRef(); b->decrRef(); diff --git a/src/MEDCoupling/Test/MEDCouplingBasicsTest4.cxx b/src/MEDCoupling/Test/MEDCouplingBasicsTest4.cxx index f781b061a..e422be808 100644 --- a/src/MEDCoupling/Test/MEDCouplingBasicsTest4.cxx +++ b/src/MEDCoupling/Test/MEDCouplingBasicsTest4.cxx @@ -2020,22 +2020,22 @@ void MEDCouplingBasicsTest4::testIntersect2DMeshesTmp1() // End of construction of input meshes m1bis and m2 -> start of specific part of the test DataArrayInt *d1=0,*d2=0; MEDCouplingUMesh *m3=MEDCouplingUMesh::Intersect2DMeshes(m1bis,m2,1e-10,d1,d2); - const int expected1[5]={0,1,1,2,2}; - const int expected2[5]={0,0,1,1,2}; - CPPUNIT_ASSERT_EQUAL(5,d1->getNumberOfTuples()); - CPPUNIT_ASSERT_EQUAL(5,d2->getNumberOfTuples()); - CPPUNIT_ASSERT_EQUAL(5,m3->getNumberOfCells()); + const int expected1[8]={0,0,1,1,1,2,2,2}; + const int expected2[8]={0,-1,0,1,-1,1,2,-1}; + CPPUNIT_ASSERT_EQUAL(8,d1->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(8,d2->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(8,m3->getNumberOfCells()); CPPUNIT_ASSERT_EQUAL(22,m3->getNumberOfNodes()); CPPUNIT_ASSERT_EQUAL(2,m3->getSpaceDimension()); - CPPUNIT_ASSERT(std::equal(expected1,expected1+5,d1->getConstPointer())); - CPPUNIT_ASSERT(std::equal(expected2,expected2+5,d2->getConstPointer())); - const int expected3[25]={5,17,1,16,12,5,18,1,17,13,5,19,2,18,13,5,20,2,19,14,5,21,3,20,14}; - const int expected4[6]={0,5,10,15,20,25}; + CPPUNIT_ASSERT(std::equal(expected1,expected1+8,d1->getConstPointer())); + CPPUNIT_ASSERT(std::equal(expected2,expected2+8,d2->getConstPointer())); + const int expected3[44]={5,17,1,16,12,5,16,0,4,5,17,12,5,18,1,17,13,5,19,2,18,13,5,17,5,6,19,13,5,20,2,19,14,5,21,3,20,14,5,19,6,7,21,14}; + const int expected4[9]={0,5,12,17,22,28,33,38,44}; const double expected5[44]={-1.0,2.0,1.0,2.0,2.0,2.0,4.0,2.0,-1.0,4.0,1.0,4.0,2.0,4.0,4.0,4.0,-0.5,-1.5,1.5,-1.5,2.5,-1.5,4.5,-1.5,-0.5,2.5,1.5,2.5,2.5,2.5,4.5,2.5,-0.5,2.0,1.0,2.5,1.5,2.0,2.0,2.5,2.5,2.0,4.0,2.5}; - CPPUNIT_ASSERT_EQUAL(25,m3->getNodalConnectivity()->getNumberOfTuples()); - CPPUNIT_ASSERT_EQUAL(6,m3->getNodalConnectivityIndex()->getNumberOfTuples()); - CPPUNIT_ASSERT(std::equal(expected3,expected3+25,m3->getNodalConnectivity()->getConstPointer())); - CPPUNIT_ASSERT(std::equal(expected4,expected4+6,m3->getNodalConnectivityIndex()->getConstPointer())); + CPPUNIT_ASSERT_EQUAL(44,m3->getNodalConnectivity()->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(9,m3->getNodalConnectivityIndex()->getNumberOfTuples()); + CPPUNIT_ASSERT(std::equal(expected3,expected3+44,m3->getNodalConnectivity()->getConstPointer())); + CPPUNIT_ASSERT(std::equal(expected4,expected4+9,m3->getNodalConnectivityIndex()->getConstPointer())); for(int i=0;i<44;i++) CPPUNIT_ASSERT_DOUBLES_EQUAL(expected5[i],m3->getCoords()->getIJ(0,i),1e-12); d1->decrRef(); @@ -2187,23 +2187,23 @@ void MEDCouplingBasicsTest4::testIntersect2DMeshesTmp3() DataArrayInt *d1=0,*d2=0; MEDCouplingUMesh *m3=MEDCouplingUMesh::Intersect2DMeshes(m1,m2,1e-10,d1,d2); m3->unPolyze(); - const int expected1[12]={0,1,1,2,3,3,4,5,5,6,7,7}; - const int expected2[12]={0,0,1,2,2,3,4,4,5,6,6,7}; - CPPUNIT_ASSERT_EQUAL(12,d1->getNumberOfTuples()); - CPPUNIT_ASSERT_EQUAL(12,d2->getNumberOfTuples()); - CPPUNIT_ASSERT_EQUAL(12,m3->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(88,m3->getNumberOfNodes()); + const int expected1[16]={0,1,1,1,2,3,3,3,4,5,5,5,6,7,7,7}; + const int expected2[16]={0,0,1,-1,2,2,3,-1,4,4,5,-1,6,6,7,-1}; + CPPUNIT_ASSERT_EQUAL(16,d1->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(16,d2->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(16,m3->getNumberOfCells()); + CPPUNIT_ASSERT_EQUAL(104,m3->getNumberOfNodes()); CPPUNIT_ASSERT_EQUAL(2,m3->getSpaceDimension()); - CPPUNIT_ASSERT(std::equal(expected1,expected1+12,d1->getConstPointer())); - CPPUNIT_ASSERT(std::equal(expected2,expected2+12,d2->getConstPointer())); - const int expected3[100]={6,28,1,25,44,45,46,8,26,1,28,27,47,48,49,50,8,40,2,26,27,51,52,53,54,6,28,25,5,55,56,57,8,28,5,32,31,58,59,60,61,8,32,6,41,31,62,63,64,65,6,25,37,5,66,67,68,8,32,5,37,36,69,70,71,72,8,42,6,32,36,73,74,75,76,6,1,37,25,77,78,79,8,37,1,26,38,80,81,82,83,8,26,2,43,38,84,85,86,87}; - const int expected4[13]={0,7,16,25,32,41,50,57,66,75,82,91,100}; - const double expected5[176]={0.,0.,1.,0.,1.5,0.,0.,1.,0.,1.5,-1.,0.,-1.5,0.,0.,-1.,0.,-1.5,0.5,0.,1.25,0.,0.7071067811865476,0.7071067811865476,1.0606601717798214,1.0606601717798214,0.,0.5,0.,1.25,-0.7071067811865476,0.7071067811865476,-1.0606601717798214,1.0606601717798214,-0.5,0.,-1.25,0.,-0.7071067811865476,-0.7071067811865476,-1.0606601717798214,-1.0606601717798214,0.,-0.5,0.,-1.25,0.7071067811865476,-0.7071067811865476,1.0606601717798214,-1.0606601717798214,0.,0.,1.1,0.,1.1,1.,0.,1.,1.7,0.,1.7,1.,-1.1,1.,-1.1,0.,-1.7,0.,-1.7,1.,-1.7,-1.,-1.1,-1.,0.,-1.,1.1,-1.,1.7,-1.,1.118033988749895,1.,-1.118033988749895,1.,-1.118033988749895,-1.,1.118033988749895,-1.,0.7071067811865477,0.7071067811865476,0.5,0.,0.,0.5,1.05,0.,0.7071067811865475,0.7071067811865477,0.55,1.,1.1,0.5,1.4012585384440737,0.535233134659635,1.3,0.,1.1,0.5,1.1090169943749475,1.,0.,0.5,-0.5,0.,-0.7071067811865477,0.7071067811865476,-0.7071067811865475,0.7071067811865477,-1.05,0.,-1.1,0.5,-0.55,1.,-1.3,0.,-1.4012585384440737,0.5352331346596344,-1.1090169943749475,1.,-1.1,0.5,0.,-0.5,-0.7071067811865475,-0.7071067811865477,-0.5,0.,-1.05,0.,-0.7071067811865478,-0.7071067811865475,-0.55,-1.,-1.1,-0.5,-1.4012585384440732,-0.5352331346596354,-1.3,0.,-1.1,-0.5,-1.1090169943749475,-1.,0.7071067811865475,-0.7071067811865477,0.,-0.5,0.5,0.,0.7071067811865477,-0.7071067811865475,1.05,0.,1.1,-0.5,0.55,-1.,1.3,0.,1.4012585384440737,-0.535233134659635,1.1090169943749475,-1.,1.1,-0.5}; - CPPUNIT_ASSERT_EQUAL(100,m3->getNodalConnectivity()->getNumberOfTuples()); - CPPUNIT_ASSERT_EQUAL(13,m3->getNodalConnectivityIndex()->getNumberOfTuples()); - CPPUNIT_ASSERT(std::equal(expected3,expected3+100,m3->getNodalConnectivity()->getConstPointer())); - CPPUNIT_ASSERT(std::equal(expected4,expected4+13,m3->getNodalConnectivityIndex()->getConstPointer())); - for(int i=0;i<176;i++) + CPPUNIT_ASSERT(std::equal(expected1,expected1+16,d1->getConstPointer())); + CPPUNIT_ASSERT(std::equal(expected2,expected2+16,d2->getConstPointer())); + const int expected3[136]={6,28,1,25,44,45,46,8,26,1,28,27,47,48,49,50,8,40,2,26,27,51,52,53,54,8,28,4,40,27,55,56,57,58,6,28,25,5,59,60,61,8,28,5,32,31,62,63,64,65,8,32,6,41,31,66,67,68,69,8,41,4,28,31,70,71,72,73,6,25,37,5,74,75,76,8,32,5,37,36,77,78,79,80,8,42,6,32,36,81,82,83,84,8,37,8,42,36,85,86,87,88,6,1,37,25,89,90,91,8,37,1,26,38,92,93,94,95,8,26,2,43,38,96,97,98,99,8,43,8,37,38,100,101,102,103}; + const int expected4[17]={0,7,16,25,34,41,50,59,68,75,84,93,102,109,118,127,136}; + const double expected5[208]={0.,0.,1.,0.,1.5,0.,0.,1.,0.,1.5,-1.,0.,-1.5,0.,0.,-1.,0.,-1.5,0.5,0.,1.25,0.,0.7071067811865476,0.7071067811865476,1.0606601717798214,1.0606601717798214,0.,0.5,0.,1.25,-0.7071067811865476,0.7071067811865476,-1.0606601717798214,1.0606601717798214,-0.5,0.,-1.25,0.,-0.7071067811865476,-0.7071067811865476,-1.0606601717798214,-1.0606601717798214,0.,-0.5,0.,-1.25,0.7071067811865476,-0.7071067811865476,1.0606601717798214,-1.0606601717798214,0.,0.,1.1,0.,1.1,1.,0.,1.,1.7,0.,1.7,1.,-1.1,1.,-1.1,0.,-1.7,0.,-1.7,1.,-1.7,-1.,-1.1,-1.,0.,-1.,1.1,-1.,1.7,-1.,1.118033988749895,1.,-1.118033988749895,1.,-1.118033988749895,-1.,1.118033988749895,-1.,0.7071067811865477,0.7071067811865476,0.5,0.,0.,0.5,1.05,0.,0.7071067811865475,0.7071067811865477,0.55,1.,1.1,0.5,1.4012585384440737,0.535233134659635,1.3,0.,1.1,0.5,1.1090169943749475,1.,0.,1.25,0.6123724356957946,1.369306393762915,1.1090169943749475,1.,0.55,1.,0.,0.5,-0.5,0.,-0.7071067811865477,0.7071067811865476,-0.7071067811865475,0.7071067811865477,-1.05,0.,-1.1,0.5,-0.55,1.,-1.3,0.,-1.4012585384440737,0.5352331346596344,-1.1090169943749475,1.,-1.1,0.5,-0.6123724356957941,1.3693063937629155,0.,1.25,-0.55,1.,-1.1090169943749475,1.,0.,-0.5,-0.7071067811865475,-0.7071067811865477,-0.5,0.,-1.05,0.,-0.7071067811865478,-0.7071067811865475,-0.55,-1.,-1.1,-0.5,-1.4012585384440734,-0.5352331346596354,-1.3,0.,-1.1,-0.5,-1.1090169943749475,-1.,0.,-1.25,-0.6123724356957945,-1.369306393762915,-1.1090169943749475,-1.,-0.55,-1.,0.7071067811865475,-0.7071067811865477,0.,-0.5,0.5,0.,0.7071067811865477,-0.7071067811865475,1.05,0.,1.1,-0.5,0.55,-1.,1.3,0.,1.4012585384440737,-0.535233134659635,1.1090169943749475,-1.,1.1,-0.5,0.6123724356957946,-1.369306393762915,0.,-1.25,0.55,-1.,1.1090169943749475,-1.0}; + CPPUNIT_ASSERT_EQUAL(136,m3->getNodalConnectivity()->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(17,m3->getNodalConnectivityIndex()->getNumberOfTuples()); + CPPUNIT_ASSERT(std::equal(expected3,expected3+136,m3->getNodalConnectivity()->getConstPointer())); + CPPUNIT_ASSERT(std::equal(expected4,expected4+17,m3->getNodalConnectivityIndex()->getConstPointer())); + for(int i=0;i<208;i++) CPPUNIT_ASSERT_DOUBLES_EQUAL(expected5[i],m3->getCoords()->getIJ(0,i),1e-12); d1->decrRef(); d2->decrRef(); diff --git a/src/MEDCoupling/Test/MEDCouplingBasicsTest5.cxx b/src/MEDCoupling/Test/MEDCouplingBasicsTest5.cxx index 5e0d2a253..9e98601c0 100644 --- a/src/MEDCoupling/Test/MEDCouplingBasicsTest5.cxx +++ b/src/MEDCoupling/Test/MEDCouplingBasicsTest5.cxx @@ -126,23 +126,23 @@ void MEDCouplingBasicsTest5::testIntersect2DMeshesTmp4() DataArrayInt *d1=0,*d2=0; MEDCouplingUMesh *m3=MEDCouplingUMesh::Intersect2DMeshes(m2,m1,1e-10,d1,d2); m3->unPolyze(); - const int expected1[12]={0,0,1,2,2,3,4,4,5,6,6,7}; - const int expected2[12]={0,1,1,2,3,3,4,5,5,6,7,7}; - CPPUNIT_ASSERT_EQUAL(12,d1->getNumberOfTuples()); - CPPUNIT_ASSERT_EQUAL(12,d2->getNumberOfTuples()); - CPPUNIT_ASSERT_EQUAL(12,m3->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(88,m3->getNumberOfNodes()); + const int expected1[16]={0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7}; + const int expected2[16]={0,1,1,-1,2,3,3,-1,4,5,5,-1,6,7,7,-1}; + CPPUNIT_ASSERT_EQUAL(16,d1->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(16,d2->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(16,m3->getNumberOfCells()); + CPPUNIT_ASSERT_EQUAL(104,m3->getNumberOfNodes()); CPPUNIT_ASSERT_EQUAL(2,m3->getSpaceDimension()); - CPPUNIT_ASSERT(std::equal(expected1,expected1+12,d1->getConstPointer())); - CPPUNIT_ASSERT(std::equal(expected2,expected2+12,d2->getConstPointer())); - const int expected3[100]={6,16,15,18,44,45,46,8,18,2,1,16,47,48,49,50,8,17,1,2,40,51,52,53,54,6,18,15,20,55,56,57,8,20,7,6,18,58,59,60,61,8,41,6,7,21,62,63,64,65,6,20,15,22,66,67,68,8,22,11,7,20,69,70,71,72,8,21,7,11,42,73,74,75,76,6,22,15,16,77,78,79,8,16,1,13,22,80,81,82,83,8,43,13,1,17,84,85,86,87}; - const int expected4[13]={0,7,16,25,32,41,50,57,66,75,82,91,100}; - const double expected5[176]={0.,0.,1.1,0.,1.1,1.,0.,1.,1.7,0.,1.7,1.,-1.1,1.,-1.1,0.,-1.7,0.,-1.7,1.,-1.7,-1.,-1.1,-1.,0.,-1.,1.1,-1.,1.7,-1.,0.,0.,1.,0.,1.5,0.,0.,1.,0.,1.5,-1.,0.,-1.5,0.,0.,-1.,0.,-1.5,0.5,0.,1.25,0.,0.7071067811865476,0.7071067811865476,1.0606601717798214,1.0606601717798214,0.,0.5,0.,1.25,-0.7071067811865476,0.7071067811865476,-1.0606601717798214,1.0606601717798214,-0.5,0.,-1.25,0.,-0.7071067811865476,-0.7071067811865476,-1.0606601717798214,-1.0606601717798214,0.,-0.5,0.,-1.25,0.7071067811865476,-0.7071067811865476,1.0606601717798214,-1.0606601717798214,1.1180339887498951,1.,-1.1180339887498951,1.,-1.1180339887498951,-1.,1.1180339887498951,-1.,0.5,0.,0.,0.5,0.7071067811865477,0.7071067811865476,0.55,1.,1.1,0.5,1.05,0.,0.7071067811865477,0.7071067811865477,1.3,0.,1.1,0.5,1.1090169943749475,1.,1.4012585384440737,0.535233134659635,0.,0.5,-0.5,0.,-0.7071067811865477,0.7071067811865476,-1.05,0.,-1.1,0.5,-0.55,1.,-0.7071067811865477,0.7071067811865477,-1.1090169943749475,1.,-1.1,0.5,-1.3,0.,-1.4012585384440737,0.5352331346596344,-0.5,0.,0.,-0.5,-0.7071067811865475,-0.7071067811865477,-0.55,-1.,-1.1,-0.5,-1.05,0.,-0.7071067811865479,-0.7071067811865476,-1.3,0.,-1.1,-0.5,-1.1090169943749475,-1.,-1.4012585384440734,-0.5352331346596354,0.,-0.5,0.5,0.,0.7071067811865475,-0.7071067811865477,1.05,0.,1.1,-0.5,0.55,-1.,0.7071067811865477,-0.7071067811865476,1.1090169943749475,-1.,1.1,-0.5,1.3,0.,1.4012585384440737,-0.535233134659635}; - CPPUNIT_ASSERT_EQUAL(100,m3->getNodalConnectivity()->getNumberOfTuples()); - CPPUNIT_ASSERT_EQUAL(13,m3->getNodalConnectivityIndex()->getNumberOfTuples()); - CPPUNIT_ASSERT(std::equal(expected3,expected3+100,m3->getNodalConnectivity()->getConstPointer())); - CPPUNIT_ASSERT(std::equal(expected4,expected4+13,m3->getNodalConnectivityIndex()->getConstPointer())); - for(int i=0;i<176;i++) + CPPUNIT_ASSERT(std::equal(expected1,expected1+16,d1->getConstPointer())); + CPPUNIT_ASSERT(std::equal(expected2,expected2+16,d2->getConstPointer())); + const int expected3[136]={6,16,15,18,44,45,46,8,18,2,1,16,47,48,49,50,8,17,1,2,40,51,52,53,54,8,40,5,4,17,55,56,57,58,6,18,15,20,59,60,61,8,20,7,6,18,62,63,64,65,8,41,6,7,21,66,67,68,69,8,21,8,9,41,70,71,72,73,6,20,15,22,74,75,76,8,22,11,7,20,77,78,79,80,8,21,7,11,42,81,82,83,84,8,42,10,8,21,85,86,87,88,6,22,15,16,89,90,91,8,16,1,13,22,92,93,94,95,8,43,13,1,17,96,97,98,99,8,17,4,14,43,100,101,102,103}; + const int expected4[17]={0,7,16,25,34,41,50,59,68,75,84,93,102,109,118,127,136}; + const double expected5[208]={0.,0.,1.1, 0.,1.1,1.,0.,1.,1.7,0.,1.7,1.,-1.1,1.,-1.1,0.,-1.7,0.,-1.7,1.,-1.7,-1.,-1.1,-1.,0.,-1.,1.1,-1.,1.7,-1.,0.,0.,1.,0.,1.5,0.,0.,1.,0.,1.5,-1.,0.,-1.5,0.,0.,-1.,0.,-1.5,0.5,0.,1.25,0.,0.7071067811865476,0.7071067811865476,1.0606601717798214,1.0606601717798214,0.,0.5,0.,1.25,-0.7071067811865476,0.7071067811865476,-1.0606601717798214,1.0606601717798214,-0.5,0.,-1.25,0.,-0.7071067811865476,-0.7071067811865476,-1.0606601717798214,-1.0606601717798214,0.,-0.5,0.,-1.25,0.7071067811865476,-0.7071067811865476,1.0606601717798214,-1.0606601717798214,1.1180339887498951,1.,-1.1180339887498951,1.,-1.1180339887498951,-1.,1.1180339887498951,-1.,0.5,0.,0.,0.5,0.7071067811865477,0.7071067811865476,0.55,1.,1.1,0.5,1.05,0.,0.7071067811865477,0.7071067811865475,1.3,0.,1.1,0.5,1.1090169943749475,1.,1.4012585384440737,0.535233134659635,1.4090169943749475,1.,1.7,0.5,1.6,0.,1.4012585384440737,0.535233134659635,0.,0.5,-0.5,0.,-0.7071067811865477,0.7071067811865476,-1.05,0.,-1.1,0.5,-0.55,1.,-0.7071067811865478,0.7071067811865475,-1.1090169943749475,1.,-1.1,0.5,-1.3,0.,-1.4012585384440737,0.5352331346596344,-1.6,0.,-1.7,0.5,-1.4090169943749475,1.,-1.4012585384440737,0.5352331346596344,-0.5,0.,0.,-0.5,-0.7071067811865475,-0.7071067811865477,-0.55,-1.,-1.1,-0.5,-1.05,0.,-0.7071067811865475,-0.7071067811865477,-1.3,0.,-1.1,-0.5,-1.1090169943749475,-1.,-1.4012585384440734,-0.5352331346596354,-1.4090169943749475,-1.,-1.7,-0.5,-1.6,0.,-1.4012585384440732,-0.5352331346596354,0.,-0.5,0.5,0.,0.7071067811865475,-0.7071067811865477,1.05,0.,1.1,-0.5,0.55,-1.,0.7071067811865475,-0.7071067811865477,1.1090169943749475,-1.,1.1,-0.5,1.3,0.,1.4012585384440737,-0.535233134659635,1.6,0.,1.7,-0.5,1.4090169943749475,-1.,1.4012585384440737,-0.535233134659635}; + CPPUNIT_ASSERT_EQUAL(136,m3->getNodalConnectivity()->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(17,m3->getNodalConnectivityIndex()->getNumberOfTuples()); + CPPUNIT_ASSERT(std::equal(expected3,expected3+136,m3->getNodalConnectivity()->getConstPointer())); + CPPUNIT_ASSERT(std::equal(expected4,expected4+17,m3->getNodalConnectivityIndex()->getConstPointer())); + for(int i=0;i<208;i++) CPPUNIT_ASSERT_DOUBLES_EQUAL(expected5[i],m3->getCoords()->getIJ(0,i),1e-12); d1->decrRef(); d2->decrRef(); @@ -1554,3 +1554,121 @@ void MEDCouplingBasicsTest5::testDuplicateEachTupleNTimes1() d4->decrRef(); d5->decrRef(); } + +void MEDCouplingBasicsTest5::testIntersect2DMeshesTmp5() +{ + // coordinates + DataArrayDouble *coords=DataArrayDouble::New(); + const double coordsData[376]={41,0,42,0,0,42,0,41,41.5,0,29.698484809834998,29.698484809834994,0,41.5,28.991378028648452,28.991378028648445,-42,0,-41,0,-29.698484809834994,29.698484809834998,-41.5,0,-28.991378028648445,28.991378028648452,0,-42,0,-41,-29.698484809835001,-29.698484809834994,0,-41.5,-28.991378028648455,-28.991378028648445,29.698484809834987,-29.698484809835001,28.991378028648441,-28.991378028648455,43,0,0,43,42.5,0,30.405591591021544,30.40559159102154,0,42.5,-43,0,-30.40559159102154,30.405591591021544,-42.5,0,0,-43,-30.405591591021551,-30.40559159102154,0,-42.5,30.405591591021537,-30.405591591021551,44,0,0,44,43.5,0,31.112698372208094,31.112698372208087,0,43.5,-44,0,-31.112698372208087,31.112698372208094,-43.5,0,0,-44,-31.112698372208097,-31.112698372208087,0,-43.5,31.112698372208083,-31.112698372208097,45,0,0,45,44.5,0,31.81980515339464,31.819805153394636,0,44.5,-45,0,-31.819805153394636,31.81980515339464,-44.5,0,0,-45,-31.819805153394647,-31.819805153394636,0,-44.5,31.819805153394629,-31.819805153394647,47,0,0,47,46,0,33.234018715767739,33.234018715767732,0,46,-47,0,-33.234018715767732,33.234018715767739,-46,0,0,-47,-33.234018715767739,-33.234018715767732,0,-46,33.234018715767725,-33.234018715767739,49,0,0,49,48,0,34.648232278140831,34.648232278140824,0,48,-49,0,-34.648232278140824,34.648232278140831,-48,0,0,-49,-34.648232278140839,-34.648232278140824,0,-48,34.648232278140817,-34.648232278140839,51,0,0,51,50,0,36.062445840513924,36.062445840513924,0,50,-51,0,-36.062445840513924,36.062445840513924,-50,0,0,-51,-36.062445840513931,-36.062445840513924,0,-50,36.062445840513917,-36.062445840513931,53,0,0,53,52,0,37.476659402887023,37.476659402887016,0,52,-53,0,-37.476659402887016,37.476659402887023,-52,0,0,-53,-37.47665940288703,-37.476659402887016,0,-52,37.476659402887009,-37.47665940288703,55,0,0,55,54,0,38.890872965260115,38.890872965260108,0,54,-55,0,-38.890872965260108,38.890872965260115,-54,0,0,-55,-38.890872965260122,-38.890872965260108,0,-54,38.890872965260101,-38.890872965260122,59,0,0,59,57,0,41.719300090006307,41.7193000900063,0,57,-59,0,-41.7193000900063,41.719300090006307,-57,0,0,-59,-41.719300090006314,-41.7193000900063,0,-57,41.719300090006293,-41.719300090006314,63,0,0,63,61,0,44.547727214752499,44.547727214752491,0,61,-63,0,-44.547727214752491,44.547727214752499,-61,0,0,-63,-44.547727214752506,-44.547727214752491,0,-61,44.547727214752484,-44.547727214752506,67,0,0,67,65,0,47.37615433949869,47.376154339498683,0,65,-67,0,-47.376154339498683,47.37615433949869,-65,0,0,-67,-47.376154339498697,-47.376154339498683,0,-65,47.376154339498676,-47.376154339498697,71,0,0,71,69,0,50.204581464244875,50.204581464244868,0,69,-71,0,-50.204581464244868,50.204581464244875,-69,0,0,-71,-50.204581464244889,-50.204581464244868,0,-69,50.20458146424486,-50.204581464244889,75,0,0,75,73,0,53.033008588991066,53.033008588991059,0,73,-75,0,-53.033008588991059,53.033008588991066,-73,0,0,-75,-53.033008588991073,-53.033008588991059,0,-73,53.033008588991052,-53.033008588991073,80,0,0,80,77.5,0,56.568542494923804,56.568542494923797,0,77.5,-80,0,-56.568542494923797,56.568542494923804,-77.5,0,0,-80,-56.568542494923818,-56.568542494923797,0,-77.5,56.56854249492379,-56.568542494923818}; + coords->useArray(coordsData,false,CPP_DEALLOC,188,2); + coords->setName(""); + DataArrayInt *conn=DataArrayInt::New(); + const int connData[540]={8,0,1,2,3,4,5,6,7,8,3,2,8,9,6,10,11,12,8,9,8,13,14,11,15,16,17,8,14,13,1,0,16,18,4,19,8,1,20,21,2,22,23,24,5,8,2,21,25,8,24,26,27,10,8,8,25,28,13,27,29,30,15,8,13,28,20,1,30,31,22,18,8,20,32,33,21,34,35,36,23,8,21,33,37,25,36,38,39,26,8,25,37,40,28,39,41,42,29,8,28,40,32,20,42,43,34,31,8,32,44,45,33,46,47,48,35,8,33,45,49,37,48,50,51,38,8,37,49,52,40,51,53,54,41,8,40,52,44,32,54,55,46,43,8,44,56,57,45,58,59,60,47,8,45,57,61,49,60,62,63,50,8,49,61,64,52,63,65,66,53,8,52,64,56,44,66,67,58,55,8,56,68,69,57,70,71,72,59,8,57,69,73,61,72,74,75,62,8,61,73,76,64,75,77,78,65,8,64,76,68,56,78,79,70,67,8,68,80,81,69,82,83,84,71,8,69,81,85,73,84,86,87,74,8,73,85,88,76,87,89,90,77,8,76,88,80,68,90,91,82,79,8,80,92,93,81,94,95,96,83,8,81,93,97,85,96,98,99,86,8,85,97,100,88,99,101,102,89,8,88,100,92,80,102,103,94,91,8,92,104,105,93,106,107,108,95,8,93,105,109,97,108,110,111,98,8,97,109,112,100,111,113,114,101,8,100,112,104,92,114,115,106,103,8,104,116,117,105,118,119,120,107,8,105,117,121,109,120,122,123,110,8,109,121,124,112,123,125,126,113,8,112,124,116,104,126,127,118,115,8,116,128,129,117,130,131,132,119,8,117,129,133,121,132,134,135,122,8,121,133,136,124,135,137,138,125,8,124,136,128,116,138,139,130,127,8,128,140,141,129,142,143,144,131,8,129,141,145,133,144,146,147,134,8,133,145,148,136,147,149,150,137,8,136,148,140,128,150,151,142,139,8,140,152,153,141,154,155,156,143,8,141,153,157,145,156,158,159,146,8,145,157,160,148,159,161,162,149,8,148,160,152,140,162,163,154,151,8,152,164,165,153,166,167,168,155,8,153,165,169,157,168,170,171,158,8,157,169,172,160,171,173,174,161,8,160,172,164,152,174,175,166,163,8,164,176,177,165,178,179,180,167,8,165,177,181,169,180,182,183,170,8,169,181,184,172,183,185,186,173,8,172,184,176,164,186,187,178,175}; + conn->useArray(connData,false,CPP_DEALLOC,540,1); + conn->setName(""); + DataArrayInt *connI=DataArrayInt::New(); + const int connIData[61]={0,9,18,27,36,45,54,63,72,81,90,99,108,117,126,135,144,153,162,171,180,189,198,207,216,225,234,243,252,261,270,279,288,297,306,315,324,333,342,351,360,369,378,387,396,405,414,423,432,441,450,459,468,477,486,495,504,513,522,531,540}; + connI->useArray(connIData,false,CPP_DEALLOC,61,1); + connI->setName(""); + // + MEDCouplingUMesh *m1=MEDCouplingUMesh::New("Fix",2); + m1->setCoords(coords); + m1->setConnectivity(conn,connI,true); + coords->decrRef(); conn->decrRef(); connI->decrRef(); + // + coords=DataArrayDouble::New(); + const double coordsData2[84]={46.5,-2.5,53.5,-2.5,53.5,2.5,46.5,2.5,50,-2.5,53.5,0,50,2.5,46.5,0,60.5,-2.5,60.5,2.5,57,-2.5,60.5,0,57,2.5,53.5,7.5,46.5,7.5,53.5,5,50,7.5,46.5,5,60.5,7.5,60.5,5,57,7.5,-2,47,2,47,2,53,-2,53,0,47,2,50,0,53,-2,50,6,47,6,53,4,47,6,50,4,53,2,59,-2,59,2,56,0,59,-2,56,6,59,6,56,4,59}; + coords->useArray(coordsData2,false,CPP_DEALLOC,42,2); + coords->setName(""); + // connectivity + conn=DataArrayInt::New(); + const int connData2[72]={8,0,1,2,3,4,5,6,7,8,1,8,9,2,10,11,12,5,8,3,2,13,14,6,15,16,17,8,2,9,18,13,12,19,20,15,8,21,22,23,24,25,26,27,28,8,22,29,30,23,31,32,33,26,8,24,23,34,35,27,36,37,38,8,23,30,39,34,33,40,41,36}; + conn->useArray(connData2,false,CPP_DEALLOC,72,1); + conn->setName(""); + connI=DataArrayInt::New(); + const int connIData2[9]={0,9,18,27,36,45,54,63,72}; + connI->useArray(connIData2,false,CPP_DEALLOC,9,1); + connI->setName(""); + MEDCouplingUMesh *m2=MEDCouplingUMesh::New("Mobile",2); + m2->setCoords(coords); + m2->setConnectivity(conn,connI,true); + coords->decrRef(); conn->decrRef(); connI->decrRef(); + // + DataArrayInt *d1=0,*d2=0; + MEDCouplingUMesh *m3=MEDCouplingUMesh::Intersect2DMeshes(m1,m2,1e-10,d1,d2); + CPPUNIT_ASSERT_EQUAL(105,m3->getNumberOfCells()); + CPPUNIT_ASSERT_EQUAL(105,d1->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(105,d2->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(704,m3->getNumberOfNodes()); + // + const double areaExpected[105]={-65.18804756198824,-65.18804756198824,-65.18804756198824,-65.18804756198824,-66.75884388878285,-66.75884388878285,-66.7588438887833,-66.75884388878308,-68.32964021557768,-68.32964021557768,-68.32964021557814,-68.32964021557791,-69.9004365423732,-69.9004365423732,-69.90043654237297,-69.90043654237297,-1.194568659706448,-1.0869994447159463,-142.2316939607081,-144.51326206513068,-144.5132620651309,-1.1945686597064424,-143.3186934054243,-5.002264310862817,-10.0261332846393,-3.9727823117092953,-7.290862524642649,-124.504404940456,-3.9727823117093237,-146.82366506060032,-150.79644737231024,-5.002264310862776,-145.79418306144626,-5.00208651738126,-10.054764051268958,-4.001067863263231,-8.027932154428669,-129.99378209314813,-4.001067863263216,-153.07856481622616,-157.0796326794898,-5.0020865173811915,-152.07754616210832,-5.001928880064381,-10.050590216368969,-4.00098721602491,-8.025810856794209,-136.28350081741684,-4.000987216024939,-159.36183077064402,-163.36281798667005,-5.0019288800643285,-158.36088910660442,-1.2991516319851801,-3.702636830195414,-3.7815130030068254,-6.265364371195623,-0.02516260900254963,-0.6553944641345026,-3.975752765070567,-7.368528340442765,-142.57249927881398,-0.02516260900254963,-3.9757527650706095,-165.64508791977525,-169.64600329384803,-1.299151631985167,-3.7026368301953885,-164.6442148316677,-10.00321285677458,-20.08414323176165,-8.001644468035863,-16.042954878437143,-304.0096070742277,-8.00164446803587,-350.1399180412005,-358.1415625092368,-10.003212856774468,-348.13834965246224,-3.794150313030109,-8.65049239704272,-0.02260276689354157,-0.5885167811200915,-370.2185414798688,-0.022602766893559393,-383.2517009710623,-383.2743037379555,-3.7941503130300576,-379.48015342492505,-408.40704496667513,-408.4070449666742,-408.4070449666742,-408.4070449666742,-433.53978619538975,-433.5397861953902,-433.5397861953911,-433.53978619539066,-458.67252742410983,-458.6725274241094,-458.67252742410983,-458.6725274241089,-608.6835766330232,-608.6835766330232,-608.6835766330232,-608.6835766330241}; + const int expected1[105]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,16,17,18,19,19,20,20,20,20,20,21,21,22,23,23,24,24,24,24,24,25,25,26,27,27,28,28,28,28,28,29,29,30,31,31,32,32,32,32,32,32,32,32,32,33,33,33,34,35,35,35,36,36,36,36,36,37,37,38,39,39,40,40,40,40,40,41,41,42,43,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59}; + const int expected2[105]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,2,-1,-1,-1,0,-1,0,2,4,5,-1,4,-1,-1,0,-1,0,2,4,5,-1,4,-1,-1,0,-1,0,2,4,5,-1,4,-1,-1,0,-1,0,1,2,3,4,5,6,7,-1,4,6,-1,-1,0,1,-1,1,3,6,7,-1,6,-1,-1,1,-1,1,3,6,7,-1,6,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; + MEDCouplingFieldDouble *f3f=m3->getMeasureField(ON_CELLS); + const double *f3=f3f->getArray()->getConstPointer(); + for(int i=0;i<105;i++) + { + CPPUNIT_ASSERT_DOUBLES_EQUAL(areaExpected[i],f3[i],1e-10); + CPPUNIT_ASSERT_EQUAL(expected1[i],d1->getIJ(i,0)); + CPPUNIT_ASSERT_EQUAL(expected2[i],d2->getIJ(i,0)); + } + // + f3f->decrRef(); + m3->decrRef(); + d1->decrRef(); + d2->decrRef(); + m2->decrRef(); + m1->decrRef(); +} + +void MEDCouplingBasicsTest5::testDAIBuildUnique1() +{ + DataArrayInt *d=DataArrayInt::New(); + const int dData[14]={1,2,2,3,3,3,3,4,5,5,7,7,7,19}; + d->useArray(dData,false,CPP_DEALLOC,14,1); + const int expectedData[7]={1,2,3,4,5,7,19}; + // + DataArrayInt *e=d->buildUnique(); + CPPUNIT_ASSERT_EQUAL(7,e->getNumberOfTuples()); + CPPUNIT_ASSERT_EQUAL(1,e->getNumberOfComponents()); + for(int i=0;i<7;i++) + CPPUNIT_ASSERT_EQUAL(expectedData[i],e->getIJ(i,0)); + // + e->decrRef(); + d->decrRef(); +} + +void MEDCouplingBasicsTest5::testDAIPartitionByDifferentValues1() +{ + const int data[9]={1,0,1,2,0,2,2,-3,2}; + const int expected1[4]={-3,0,1,2}; + const int expected2_0[1]={7}; + const int expected2_1[2]={1,4}; + const int expected2_2[2]={0,2}; + const int expected2_3[4]={3,5,6,8}; + DataArrayInt *d=DataArrayInt::New(); + d->useArray(data,false,CPP_DEALLOC,9,1); + std::vector f; + static const int nbOfOutputsExpected=4; + std::vector e=d->partitionByDifferentValues(f); + d->decrRef(); + CPPUNIT_ASSERT_EQUAL(nbOfOutputsExpected,(int)e.size()); + CPPUNIT_ASSERT_EQUAL(nbOfOutputsExpected,(int)f.size()); + for(int i=0;igetNbOfElems()); + CPPUNIT_ASSERT_EQUAL(2,e[1]->getNbOfElems()); + CPPUNIT_ASSERT_EQUAL(2,e[2]->getNbOfElems()); + CPPUNIT_ASSERT_EQUAL(4,e[3]->getNbOfElems()); + CPPUNIT_ASSERT_EQUAL(1,e[0]->getNumberOfComponents()); + CPPUNIT_ASSERT_EQUAL(1,e[1]->getNumberOfComponents()); + CPPUNIT_ASSERT_EQUAL(1,e[2]->getNumberOfComponents()); + CPPUNIT_ASSERT_EQUAL(1,e[3]->getNumberOfComponents()); + CPPUNIT_ASSERT(std::equal(expected2_0,expected2_0+1,e[0]->begin())); + CPPUNIT_ASSERT(std::equal(expected2_1,expected2_1+2,e[1]->begin())); + CPPUNIT_ASSERT(std::equal(expected2_2,expected2_2+2,e[2]->begin())); + CPPUNIT_ASSERT(std::equal(expected2_3,expected2_3+4,e[3]->begin())); + e[0]->decrRef(); e[1]->decrRef(); e[2]->decrRef(); e[3]->decrRef(); +} diff --git a/src/MEDCoupling/Test/MEDCouplingBasicsTest5.hxx b/src/MEDCoupling/Test/MEDCouplingBasicsTest5.hxx index 0bc8432f6..1ee856333 100644 --- a/src/MEDCoupling/Test/MEDCouplingBasicsTest5.hxx +++ b/src/MEDCoupling/Test/MEDCouplingBasicsTest5.hxx @@ -66,6 +66,9 @@ namespace ParaMEDMEM CPPUNIT_TEST( testUnPolyze3 ); CPPUNIT_TEST( testKrSpatialDiscretization1 ); CPPUNIT_TEST( testDuplicateEachTupleNTimes1 ); + CPPUNIT_TEST( testIntersect2DMeshesTmp5 ); + CPPUNIT_TEST( testDAIBuildUnique1 ); + CPPUNIT_TEST( testDAIPartitionByDifferentValues1 ); CPPUNIT_TEST_SUITE_END(); public: void testUMeshTessellate2D1(); @@ -98,6 +101,9 @@ namespace ParaMEDMEM void testUnPolyze3(); void testKrSpatialDiscretization1(); void testDuplicateEachTupleNTimes1(); + void testIntersect2DMeshesTmp5(); + void testDAIBuildUnique1(); + void testDAIPartitionByDifferentValues1(); }; } diff --git a/src/MEDCoupling_Swig/MEDCouplingBasicsTest.py b/src/MEDCoupling_Swig/MEDCouplingBasicsTest.py index 4f63e6fd3..bc59a44de 100644 --- a/src/MEDCoupling_Swig/MEDCouplingBasicsTest.py +++ b/src/MEDCoupling_Swig/MEDCouplingBasicsTest.py @@ -1993,6 +1993,7 @@ class MEDCouplingBasicsTest(unittest.TestCase): self.assertEqual(5,f.getNumberOfMeshPlacesExpected()); self.assertEqual(0,f.getNbOfGaussLocalization()); f.setGaussLocalizationOnType(NORM_TRI3,_refCoo1,_gsCoo1,_wg1); + f.setGaussLocalizationOnType(NORM_TRI3,_refCoo1,_gsCoo1,_wg1); # not a bug only to check that it works well self.assertRaises(InterpKernelException,f.setGaussLocalizationOnType,NORM_QUAD4,_refCoo1,_gsCoo1,_wg1) self.assertEqual(1,f.getNbOfGaussLocalization()); refCoo2=[ 0.,0., 1.,0., 1.,1., 0.,1. ] @@ -8218,20 +8219,20 @@ class MEDCouplingBasicsTest(unittest.TestCase): m2.translate([0.5,0.5]) # m3,d1,d2=MEDCouplingUMesh.Intersect2DMeshes(m1bis,m2,1e-10) - expected1=[0,1,1,2,2] - expected2=[0,0,1,1,2] - self.assertEqual(5,d1.getNumberOfTuples()); - self.assertEqual(5,d2.getNumberOfTuples()); - self.assertEqual(5,m3.getNumberOfCells()); + expected1=[0,0,1,1,1,2,2,2] + expected2=[0,-1,0,1,-1,1,2,-1] + self.assertEqual(8,d1.getNumberOfTuples()); + self.assertEqual(8,d2.getNumberOfTuples()); + self.assertEqual(8,m3.getNumberOfCells()); self.assertEqual(22,m3.getNumberOfNodes()); self.assertEqual(2,m3.getSpaceDimension()); self.assertEqual(expected1,d1.getValues()); self.assertEqual(expected2,d2.getValues()); - expected3=[5,17,1,16,12,5,18,1,17,13,5,19,2,18,13,5,20,2,19,14,5,21,3,20,14] - expected4=[0,5,10,15,20,25] + expected3=[5,17,1,16,12,5,16,0,4,5,17,12,5,18,1,17,13,5,19,2,18,13,5,17,5,6,19,13,5,20,2,19,14,5,21,3,20,14,5,19,6,7,21,14] + expected4=[0,5,12,17,22,28,33,38,44] expected5=[-1.0,2.0,1.0,2.0,2.0,2.0,4.0,2.0,-1.0,4.0,1.0,4.0,2.0,4.0,4.0,4.0,-0.5,-1.5,1.5,-1.5,2.5,-1.5,4.5,-1.5,-0.5,2.5,1.5,2.5,2.5,2.5,4.5,2.5,-0.5,2.0,1.0,2.5,1.5,2.0,2.0,2.5,2.5,2.0,4.0,2.5] - self.assertEqual(25,m3.getNodalConnectivity().getNumberOfTuples()); - self.assertEqual(6,m3.getNodalConnectivityIndex().getNumberOfTuples()); + self.assertEqual(44,m3.getNodalConnectivity().getNumberOfTuples()); + self.assertEqual(9,m3.getNodalConnectivityIndex().getNumberOfTuples()); self.assertEqual(expected3,m3.getNodalConnectivity().getValues()); self.assertEqual(expected4,m3.getNodalConnectivityIndex().getValues()); for i in xrange(44): @@ -8345,23 +8346,23 @@ class MEDCouplingBasicsTest(unittest.TestCase): m3,d1,d2=MEDCouplingUMesh.Intersect2DMeshes(m1,m2,1e-10) m3.unPolyze() # - expected1=[0,1,1,2,3,3,4,5,5,6,7,7] - expected2=[0,0,1,2,2,3,4,4,5,6,6,7] - self.assertEqual(12,d1.getNumberOfTuples()); - self.assertEqual(12,d2.getNumberOfTuples()); - self.assertEqual(12,m3.getNumberOfCells()); - self.assertEqual(88,m3.getNumberOfNodes()); + expected1=[0,1,1,1,2,3,3,3,4,5,5,5,6,7,7,7] + expected2=[0,0,1,-1,2,2,3,-1,4,4,5,-1,6,6,7,-1] + self.assertEqual(16,d1.getNumberOfTuples()); + self.assertEqual(16,d2.getNumberOfTuples()); + self.assertEqual(16,m3.getNumberOfCells()); + self.assertEqual(104,m3.getNumberOfNodes()); self.assertEqual(2,m3.getSpaceDimension()); self.assertEqual(expected1,d1.getValues()); self.assertEqual(expected2,d2.getValues()); - expected3=[6,28,1,25,44,45,46,8,26,1,28,27,47,48,49,50,8,40,2,26,27,51,52,53,54,6,28,25,5,55,56,57,8,28,5,32,31,58,59,60,61,8,32,6,41,31,62,63,64,65,6,25,37,5,66,67,68,8,32,5,37,36,69,70,71,72,8,42,6,32,36,73,74,75,76,6,1,37,25,77,78,79,8,37,1,26,38,80,81,82,83,8,26,2,43,38,84,85,86,87] - expected4=[0,7,16,25,32,41,50,57,66,75,82,91,100] - expected5=[0.,0.,1.,0.,1.5,0.,0.,1.,0.,1.5,-1.,0.,-1.5,0.,0.,-1.,0.,-1.5,0.5,0.,1.25,0.,0.7071067811865476,0.7071067811865476,1.0606601717798214,1.0606601717798214,0.,0.5,0.,1.25,-0.7071067811865476,0.7071067811865476,-1.0606601717798214,1.0606601717798214,-0.5,0.,-1.25,0.,-0.7071067811865476,-0.7071067811865476,-1.0606601717798214,-1.0606601717798214,0.,-0.5,0.,-1.25,0.7071067811865476,-0.7071067811865476,1.0606601717798214,-1.0606601717798214,0.,0.,1.1,0.,1.1,1.,0.,1.,1.7,0.,1.7,1.,-1.1,1.,-1.1,0.,-1.7,0.,-1.7,1.,-1.7,-1.,-1.1,-1.,0.,-1.,1.1,-1.,1.7,-1.,1.118033988749895,1.,-1.118033988749895,1.,-1.118033988749895,-1.,1.118033988749895,-1.,0.7071067811865477,0.7071067811865476,0.5,0.,0.,0.5,1.05,0.,0.7071067811865475,0.7071067811865477,0.55,1.,1.1,0.5,1.4012585384440737,0.535233134659635,1.3,0.,1.1,0.5,1.1090169943749475,1.,0.,0.5,-0.5,0.,-0.7071067811865477,0.7071067811865476,-0.7071067811865475,0.7071067811865477,-1.05,0.,-1.1,0.5,-0.55,1.,-1.3,0.,-1.4012585384440737,0.5352331346596344,-1.1090169943749475,1.,-1.1,0.5,0.,-0.5,-0.7071067811865475,-0.7071067811865477,-0.5,0.,-1.05,0.,-0.7071067811865478,-0.7071067811865475,-0.55,-1.,-1.1,-0.5,-1.4012585384440732,-0.5352331346596354,-1.3,0.,-1.1,-0.5,-1.1090169943749475,-1.,0.7071067811865475,-0.7071067811865477,0.,-0.5,0.5,0.,0.7071067811865477,-0.7071067811865475,1.05,0.,1.1,-0.5,0.55,-1.,1.3,0.,1.4012585384440737,-0.535233134659635,1.1090169943749475,-1.,1.1,-0.5] - self.assertEqual(100,m3.getNodalConnectivity().getNumberOfTuples()); - self.assertEqual(13,m3.getNodalConnectivityIndex().getNumberOfTuples()); + expected3=[6,28,1,25,44,45,46,8,26,1,28,27,47,48,49,50,8,40,2,26,27,51,52,53,54,8,28,4,40,27,55,56,57,58,6,28,25,5,59,60,61,8,28,5,32,31,62,63,64,65,8,32,6,41,31,66,67,68,69,8,41,4,28,31,70,71,72,73,6,25,37,5,74,75,76,8,32,5,37,36,77,78,79,80,8,42,6,32,36,81,82,83,84,8,37,8,42,36,85,86,87,88,6,1,37,25,89,90,91,8,37,1,26,38,92,93,94,95,8,26,2,43,38,96,97,98,99,8,43,8,37,38,100,101,102,103] + expected4=[0,7,16,25,34,41,50,59,68,75,84,93,102,109,118,127,136] + expected5=[0.,0.,1.,0.,1.5,0.,0.,1.,0.,1.5,-1.,0.,-1.5,0.,0.,-1.,0.,-1.5,0.5,0.,1.25,0.,0.7071067811865476,0.7071067811865476,1.0606601717798214,1.0606601717798214,0.,0.5,0.,1.25,-0.7071067811865476,0.7071067811865476,-1.0606601717798214,1.0606601717798214,-0.5,0.,-1.25,0.,-0.7071067811865476,-0.7071067811865476,-1.0606601717798214,-1.0606601717798214,0.,-0.5,0.,-1.25,0.7071067811865476,-0.7071067811865476,1.0606601717798214,-1.0606601717798214,0.,0.,1.1,0.,1.1,1.,0.,1.,1.7,0.,1.7,1.,-1.1,1.,-1.1,0.,-1.7,0.,-1.7,1.,-1.7,-1.,-1.1,-1.,0.,-1.,1.1,-1.,1.7,-1.,1.118033988749895,1.,-1.118033988749895,1.,-1.118033988749895,-1.,1.118033988749895,-1.,0.7071067811865477,0.7071067811865476,0.5,0.,0.,0.5,1.05,0.,0.7071067811865475,0.7071067811865477,0.55,1.,1.1,0.5,1.4012585384440737,0.535233134659635,1.3,0.,1.1,0.5,1.1090169943749475,1.,0.,1.25,0.6123724356957946,1.369306393762915,1.1090169943749475,1.,0.55,1.,0.,0.5,-0.5,0.,-0.7071067811865477,0.7071067811865476,-0.7071067811865475,0.7071067811865477,-1.05,0.,-1.1,0.5,-0.55,1.,-1.3,0.,-1.4012585384440737,0.5352331346596344,-1.1090169943749475,1.,-1.1,0.5,-0.6123724356957941,1.3693063937629155,0.,1.25,-0.55,1.,-1.1090169943749475,1.,0.,-0.5,-0.7071067811865475,-0.7071067811865477,-0.5,0.,-1.05,0.,-0.7071067811865478,-0.7071067811865475,-0.55,-1.,-1.1,-0.5,-1.4012585384440734,-0.5352331346596354,-1.3,0.,-1.1,-0.5,-1.1090169943749475,-1.,0.,-1.25,-0.6123724356957945,-1.369306393762915,-1.1090169943749475,-1.,-0.55,-1.,0.7071067811865475,-0.7071067811865477,0.,-0.5,0.5,0.,0.7071067811865477,-0.7071067811865475,1.05,0.,1.1,-0.5,0.55,-1.,1.3,0.,1.4012585384440737,-0.535233134659635,1.1090169943749475,-1.,1.1,-0.5,0.6123724356957946,-1.369306393762915,0.,-1.25,0.55,-1.,1.1090169943749475,-1.0] + self.assertEqual(136,m3.getNodalConnectivity().getNumberOfTuples()); + self.assertEqual(17,m3.getNodalConnectivityIndex().getNumberOfTuples()); self.assertEqual(expected3,m3.getNodalConnectivity().getValues()); self.assertEqual(expected4,m3.getNodalConnectivityIndex().getValues()); - for i in xrange(176): + for i in xrange(208): self.assertAlmostEqual(expected5[i],m3.getCoords().getIJ(0,i),12); pass pass @@ -8445,23 +8446,23 @@ class MEDCouplingBasicsTest(unittest.TestCase): m3,d1,d2=MEDCouplingUMesh.Intersect2DMeshes(m2,m1,1e-10) m3.unPolyze() # - expected1=[0,0,1,2,2,3,4,4,5,6,6,7] - expected2=[0,1,1,2,3,3,4,5,5,6,7,7] - self.assertEqual(12,d1.getNumberOfTuples()); - self.assertEqual(12,d2.getNumberOfTuples()); - self.assertEqual(12,m3.getNumberOfCells()); - self.assertEqual(88,m3.getNumberOfNodes()); + expected1=[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7] + expected2=[0,1,1,-1,2,3,3,-1,4,5,5,-1,6,7,7,-1] + self.assertEqual(16,d1.getNumberOfTuples()); + self.assertEqual(16,d2.getNumberOfTuples()); + self.assertEqual(16,m3.getNumberOfCells()); + self.assertEqual(104,m3.getNumberOfNodes()); self.assertEqual(2,m3.getSpaceDimension()); self.assertEqual(expected1,d1.getValues()); self.assertEqual(expected2,d2.getValues()); - expected3=[6,16,15,18,44,45,46,8,18,2,1,16,47,48,49,50,8,17,1,2,40,51,52,53,54,6,18,15,20,55,56,57,8,20,7,6,18,58,59,60,61,8,41,6,7,21,62,63,64,65,6,20,15,22,66,67,68,8,22,11,7,20,69,70,71,72,8,21,7,11,42,73,74,75,76,6,22,15,16,77,78,79,8,16,1,13,22,80,81,82,83,8,43,13,1,17,84,85,86,87] - expected4=[0,7,16,25,32,41,50,57,66,75,82,91,100] - expected5=[0.,0.,1.1,0.,1.1,1.,0.,1.,1.7,0.,1.7,1.,-1.1,1.,-1.1,0.,-1.7,0.,-1.7,1.,-1.7,-1.,-1.1,-1.,0.,-1.,1.1,-1.,1.7,-1.,0.,0.,1.,0.,1.5,0.,0.,1.,0.,1.5,-1.,0.,-1.5,0.,0.,-1.,0.,-1.5,0.5,0.,1.25,0.,0.7071067811865476,0.7071067811865476,1.0606601717798214,1.0606601717798214,0.,0.5,0.,1.25,-0.7071067811865476,0.7071067811865476,-1.0606601717798214,1.0606601717798214,-0.5,0.,-1.25,0.,-0.7071067811865476,-0.7071067811865476,-1.0606601717798214,-1.0606601717798214,0.,-0.5,0.,-1.25,0.7071067811865476,-0.7071067811865476,1.0606601717798214,-1.0606601717798214,1.1180339887498951,1.,-1.1180339887498951,1.,-1.1180339887498951,-1.,1.1180339887498951,-1.,0.5,0.,0.,0.5,0.7071067811865477,0.7071067811865476,0.55,1.,1.1,0.5,1.05,0.,0.7071067811865477,0.7071067811865477,1.3,0.,1.1,0.5,1.1090169943749475,1.,1.4012585384440737,0.535233134659635,0.,0.5,-0.5,0.,-0.7071067811865477,0.7071067811865476,-1.05,0.,-1.1,0.5,-0.55,1.,-0.7071067811865477,0.7071067811865477,-1.1090169943749475,1.,-1.1,0.5,-1.3,0.,-1.4012585384440737,0.5352331346596344,-0.5,0.,0.,-0.5,-0.7071067811865475,-0.7071067811865477,-0.55,-1.,-1.1,-0.5,-1.05,0.,-0.7071067811865479,-0.7071067811865476,-1.3,0.,-1.1,-0.5,-1.1090169943749475,-1.,-1.4012585384440734,-0.5352331346596354,0.,-0.5,0.5,0.,0.7071067811865475,-0.7071067811865477,1.05,0.,1.1,-0.5,0.55,-1.,0.7071067811865477,-0.7071067811865476,1.1090169943749475,-1.,1.1,-0.5,1.3,0.,1.4012585384440737,-0.535233134659635] - self.assertEqual(100,m3.getNodalConnectivity().getNumberOfTuples()); - self.assertEqual(13,m3.getNodalConnectivityIndex().getNumberOfTuples()); + expected3=[6,16,15,18,44,45,46,8,18,2,1,16,47,48,49,50,8,17,1,2,40,51,52,53,54,8,40,5,4,17,55,56,57,58,6,18,15,20,59,60,61,8,20,7,6,18,62,63,64,65,8,41,6,7,21,66,67,68,69,8,21,8,9,41,70,71,72,73,6,20,15,22,74,75,76,8,22,11,7,20,77,78,79,80,8,21,7,11,42,81,82,83,84,8,42,10,8,21,85,86,87,88,6,22,15,16,89,90,91,8,16,1,13,22,92,93,94,95,8,43,13,1,17,96,97,98,99,8,17,4,14,43,100,101,102,103] + expected4=[0,7,16,25,34,41,50,59,68,75,84,93,102,109,118,127,136] + expected5=[0.,0.,1.1, 0.,1.1,1.,0.,1.,1.7,0.,1.7,1.,-1.1,1.,-1.1,0.,-1.7,0.,-1.7,1.,-1.7,-1.,-1.1,-1.,0.,-1.,1.1,-1.,1.7,-1.,0.,0.,1.,0.,1.5,0.,0.,1.,0.,1.5,-1.,0.,-1.5,0.,0.,-1.,0.,-1.5,0.5,0.,1.25,0.,0.7071067811865476,0.7071067811865476,1.0606601717798214,1.0606601717798214,0.,0.5,0.,1.25,-0.7071067811865476,0.7071067811865476,-1.0606601717798214,1.0606601717798214,-0.5,0.,-1.25,0.,-0.7071067811865476,-0.7071067811865476,-1.0606601717798214,-1.0606601717798214,0.,-0.5,0.,-1.25,0.7071067811865476,-0.7071067811865476,1.0606601717798214,-1.0606601717798214,1.1180339887498951,1.,-1.1180339887498951,1.,-1.1180339887498951,-1.,1.1180339887498951,-1.,0.5,0.,0.,0.5,0.7071067811865477,0.7071067811865476,0.55,1.,1.1,0.5,1.05,0.,0.7071067811865477,0.7071067811865475,1.3,0.,1.1,0.5,1.1090169943749475,1.,1.4012585384440737,0.535233134659635,1.4090169943749475,1.,1.7,0.5,1.6,0.,1.4012585384440737,0.535233134659635,0.,0.5,-0.5,0.,-0.7071067811865477,0.7071067811865476,-1.05,0.,-1.1,0.5,-0.55,1.,-0.7071067811865478,0.7071067811865475,-1.1090169943749475,1.,-1.1,0.5,-1.3,0.,-1.4012585384440737,0.5352331346596344,-1.6,0.,-1.7,0.5,-1.4090169943749475,1.,-1.4012585384440737,0.5352331346596344,-0.5,0.,0.,-0.5,-0.7071067811865475,-0.7071067811865477,-0.55,-1.,-1.1,-0.5,-1.05,0.,-0.7071067811865475,-0.7071067811865477,-1.3,0.,-1.1,-0.5,-1.1090169943749475,-1.,-1.4012585384440734,-0.5352331346596354,-1.4090169943749475,-1.,-1.7,-0.5,-1.6,0.,-1.4012585384440732,-0.5352331346596354,0.,-0.5,0.5,0.,0.7071067811865475,-0.7071067811865477,1.05,0.,1.1,-0.5,0.55,-1.,0.7071067811865475,-0.7071067811865477,1.1090169943749475,-1.,1.1,-0.5,1.3,0.,1.4012585384440737,-0.535233134659635,1.6,0.,1.7,-0.5,1.4090169943749475,-1.,1.4012585384440737,-0.535233134659635] + self.assertEqual(136,m3.getNodalConnectivity().getNumberOfTuples()); + self.assertEqual(17,m3.getNodalConnectivityIndex().getNumberOfTuples()); self.assertEqual(expected3,m3.getNodalConnectivity().getValues()); self.assertEqual(expected4,m3.getNodalConnectivityIndex().getValues()); - for i in xrange(176): + for i in xrange(208): self.assertAlmostEqual(expected5[i],m3.getCoords().getIJ(0,i),12); pass pass @@ -9243,6 +9244,54 @@ class MEDCouplingBasicsTest(unittest.TestCase): self.assertRaises(InterpKernelException,DataArrayDouble.New,vals,7,2); pass + def testSwigDADOp9(self): + l1=[(1.,2.,3),(4.,5.,6.),(7.,8.,9.),[10.,11.,12.]] + da1=DataArrayDouble(l1,4,3) + self.assertEqual(4,da1.getNumberOfTuples()); + self.assertEqual(3,da1.getNumberOfComponents()); + da2=DataArrayDouble(12) ; da2.iota(1.) ; da2.rearrange(3) + self.assertTrue(da2.isEqual(da1,1e-12)) + self.assertRaises(InterpKernelException,DataArrayDouble.New,l1,3,4); + da3=DataArrayDouble(l1,4) + self.assertTrue(da3.isEqual(da1,1e-12)) + self.assertRaises(InterpKernelException,DataArrayDouble.New,l1,3); + self.assertRaises(InterpKernelException,DataArrayDouble.New,l1,5); + l1=[(1.,2.,3),(4.,(5.),((6.))),(7.,8.,9.),[10.,11.,12.]] + da1=DataArrayDouble(l1,4,3) + self.assertEqual(4,da1.getNumberOfTuples()); + self.assertEqual(3,da1.getNumberOfComponents()); + da2=DataArrayDouble(12) ; da2.iota(1.) ; da2.rearrange(3) + self.assertTrue(da2.isEqual(da1,1e-12)) + self.assertRaises(InterpKernelException,DataArrayDouble.New,l1,3,4); + da3=DataArrayDouble(l1,4) + self.assertTrue(da3.isEqual(da1,1e-12)) + self.assertRaises(InterpKernelException,DataArrayDouble.New,l1,3); + self.assertRaises(InterpKernelException,DataArrayDouble.New,l1,5); + # + l1=[(1,2,3),(4,5,6),(7,8,9),[10,11,12]] + da1=DataArrayInt(l1,4,3) + self.assertEqual(4,da1.getNumberOfTuples()); + self.assertEqual(3,da1.getNumberOfComponents()); + da2=DataArrayInt(12) ; da2.iota(1) ; da2.rearrange(3) + self.assertTrue(da2.isEqual(da1)) + self.assertRaises(InterpKernelException,DataArrayInt.New,l1,3,4); + da3=DataArrayInt(l1,4) + self.assertTrue(da3.isEqual(da1)) + self.assertRaises(InterpKernelException,DataArrayInt.New,l1,3); + self.assertRaises(InterpKernelException,DataArrayInt.New,l1,5); + l1=[(1,[2],3),(4,[(5)],6),((([7])),8,9),[10,11,12]] + da1=DataArrayInt(l1,4,3) + self.assertEqual(4,da1.getNumberOfTuples()); + self.assertEqual(3,da1.getNumberOfComponents()); + da2=DataArrayInt(12) ; da2.iota(1) ; da2.rearrange(3) + self.assertTrue(da2.isEqual(da1)) + self.assertRaises(InterpKernelException,DataArrayInt.New,l1,3,4); + da3=DataArrayInt(l1,4) + self.assertTrue(da3.isEqual(da1)) + self.assertRaises(InterpKernelException,DataArrayInt.New,l1,3); + self.assertRaises(InterpKernelException,DataArrayInt.New,l1,5); + pass + def testRenumberNodesInConn1(self): mesh2DCoords=[-0.3,-0.3,0., 0.2,-0.3,0., 0.7,-0.3,0., -0.3,0.2,0., 0.2,0.2,0., 0.7,0.2,0., -0.3,0.7,0., 0.2,0.7,0., 0.7,0.7,0. ] mesh2DConn=[1,4,2, 4,5,2, 0,3,4,1, 6,7,4,3, 7,8,5,4] @@ -10230,6 +10279,124 @@ class MEDCouplingBasicsTest(unittest.TestCase): self.assertEqual(d.getValues(),[1,2,0,1,2,0,1,2,0,1]) pass + def testIntersect2DMeshesTmp5(self): + coords=DataArrayDouble.New([41,0,42,0,0,42,0,41,41.5,0,29.698484809834998,29.698484809834994,0,41.5,28.991378028648452,28.991378028648445,-42,0,-41,0,-29.698484809834994,29.698484809834998,-41.5,0,-28.991378028648445,28.991378028648452,0,-42,0,-41,-29.698484809835001,-29.698484809834994,0,-41.5,-28.991378028648455,-28.991378028648445,29.698484809834987,-29.698484809835001,28.991378028648441,-28.991378028648455,43,0,0,43,42.5,0,30.405591591021544,30.40559159102154,0,42.5,-43,0,-30.40559159102154,30.405591591021544,-42.5,0,0,-43,-30.405591591021551,-30.40559159102154,0,-42.5,30.405591591021537,-30.405591591021551,44,0,0,44,43.5,0,31.112698372208094,31.112698372208087,0,43.5,-44,0,-31.112698372208087,31.112698372208094,-43.5,0,0,-44,-31.112698372208097,-31.112698372208087,0,-43.5,31.112698372208083,-31.112698372208097,45,0,0,45,44.5,0,31.81980515339464,31.819805153394636,0,44.5,-45,0,-31.819805153394636,31.81980515339464,-44.5,0,0,-45,-31.819805153394647,-31.819805153394636,0,-44.5,31.819805153394629,-31.819805153394647,47,0,0,47,46,0,33.234018715767739,33.234018715767732,0,46,-47,0,-33.234018715767732,33.234018715767739,-46,0,0,-47,-33.234018715767739,-33.234018715767732,0,-46,33.234018715767725,-33.234018715767739,49,0,0,49,48,0,34.648232278140831,34.648232278140824,0,48,-49,0,-34.648232278140824,34.648232278140831,-48,0,0,-49,-34.648232278140839,-34.648232278140824,0,-48,34.648232278140817,-34.648232278140839,51,0,0,51,50,0,36.062445840513924,36.062445840513924,0,50,-51,0,-36.062445840513924,36.062445840513924,-50,0,0,-51,-36.062445840513931,-36.062445840513924,0,-50,36.062445840513917,-36.062445840513931,53,0,0,53,52,0,37.476659402887023,37.476659402887016,0,52,-53,0,-37.476659402887016,37.476659402887023,-52,0,0,-53,-37.47665940288703,-37.476659402887016,0,-52,37.476659402887009,-37.47665940288703,55,0,0,55,54,0,38.890872965260115,38.890872965260108,0,54,-55,0,-38.890872965260108,38.890872965260115,-54,0,0,-55,-38.890872965260122,-38.890872965260108,0,-54,38.890872965260101,-38.890872965260122,59,0,0,59,57,0,41.719300090006307,41.7193000900063,0,57,-59,0,-41.7193000900063,41.719300090006307,-57,0,0,-59,-41.719300090006314,-41.7193000900063,0,-57,41.719300090006293,-41.719300090006314,63,0,0,63,61,0,44.547727214752499,44.547727214752491,0,61,-63,0,-44.547727214752491,44.547727214752499,-61,0,0,-63,-44.547727214752506,-44.547727214752491,0,-61,44.547727214752484,-44.547727214752506,67,0,0,67,65,0,47.37615433949869,47.376154339498683,0,65,-67,0,-47.376154339498683,47.37615433949869,-65,0,0,-67,-47.376154339498697,-47.376154339498683,0,-65,47.376154339498676,-47.376154339498697,71,0,0,71,69,0,50.204581464244875,50.204581464244868,0,69,-71,0,-50.204581464244868,50.204581464244875,-69,0,0,-71,-50.204581464244889,-50.204581464244868,0,-69,50.20458146424486,-50.204581464244889,75,0,0,75,73,0,53.033008588991066,53.033008588991059,0,73,-75,0,-53.033008588991059,53.033008588991066,-73,0,0,-75,-53.033008588991073,-53.033008588991059,0,-73,53.033008588991052,-53.033008588991073,80,0,0,80,77.5,0,56.568542494923804,56.568542494923797,0,77.5,-80,0,-56.568542494923797,56.568542494923804,-77.5,0,0,-80,-56.568542494923818,-56.568542494923797,0,-77.5,56.56854249492379,-56.568542494923818],188,2) + conn=DataArrayInt.New([8,0,1,2,3,4,5,6,7,8,3,2,8,9,6,10,11,12,8,9,8,13,14,11,15,16,17,8,14,13,1,0,16,18,4,19,8,1,20,21,2,22,23,24,5,8,2,21,25,8,24,26,27,10,8,8,25,28,13,27,29,30,15,8,13,28,20,1,30,31,22,18,8,20,32,33,21,34,35,36,23,8,21,33,37,25,36,38,39,26,8,25,37,40,28,39,41,42,29,8,28,40,32,20,42,43,34,31,8,32,44,45,33,46,47,48,35,8,33,45,49,37,48,50,51,38,8,37,49,52,40,51,53,54,41,8,40,52,44,32,54,55,46,43,8,44,56,57,45,58,59,60,47,8,45,57,61,49,60,62,63,50,8,49,61,64,52,63,65,66,53,8,52,64,56,44,66,67,58,55,8,56,68,69,57,70,71,72,59,8,57,69,73,61,72,74,75,62,8,61,73,76,64,75,77,78,65,8,64,76,68,56,78,79,70,67,8,68,80,81,69,82,83,84,71,8,69,81,85,73,84,86,87,74,8,73,85,88,76,87,89,90,77,8,76,88,80,68,90,91,82,79,8,80,92,93,81,94,95,96,83,8,81,93,97,85,96,98,99,86,8,85,97,100,88,99,101,102,89,8,88,100,92,80,102,103,94,91,8,92,104,105,93,106,107,108,95,8,93,105,109,97,108,110,111,98,8,97,109,112,100,111,113,114,101,8,100,112,104,92,114,115,106,103,8,104,116,117,105,118,119,120,107,8,105,117,121,109,120,122,123,110,8,109,121,124,112,123,125,126,113,8,112,124,116,104,126,127,118,115,8,116,128,129,117,130,131,132,119,8,117,129,133,121,132,134,135,122,8,121,133,136,124,135,137,138,125,8,124,136,128,116,138,139,130,127,8,128,140,141,129,142,143,144,131,8,129,141,145,133,144,146,147,134,8,133,145,148,136,147,149,150,137,8,136,148,140,128,150,151,142,139,8,140,152,153,141,154,155,156,143,8,141,153,157,145,156,158,159,146,8,145,157,160,148,159,161,162,149,8,148,160,152,140,162,163,154,151,8,152,164,165,153,166,167,168,155,8,153,165,169,157,168,170,171,158,8,157,169,172,160,171,173,174,161,8,160,172,164,152,174,175,166,163,8,164,176,177,165,178,179,180,167,8,165,177,181,169,180,182,183,170,8,169,181,184,172,183,185,186,173,8,172,184,176,164,186,187,178,175],540) + connI=DataArrayInt.New([0,9,18,27,36,45,54,63,72,81,90,99,108,117,126,135,144,153,162,171,180,189,198,207,216,225,234,243,252,261,270,279,288,297,306,315,324,333,342,351,360,369,378,387,396,405,414,423,432,441,450,459,468,477,486,495,504,513,522,531,540],61) + # + m1=MEDCouplingUMesh.New("Fix",2); + m1.setCoords(coords); + m1.setConnectivity(conn,connI,True); + # + coords=DataArrayDouble([46.5,-2.5,53.5,-2.5,53.5,2.5,46.5,2.5,50,-2.5,53.5,0,50,2.5,46.5,0,60.5,-2.5,60.5,2.5,57,-2.5,60.5,0,57,2.5,53.5,7.5,46.5,7.5,53.5,5,50,7.5,46.5,5,60.5,7.5,60.5,5,57,7.5,-2,47,2,47,2,53,-2,53,0,47,2,50,0,53,-2,50,6,47,6,53,4,47,6,50,4,53,2,59,-2,59,2,56,0,59,-2,56,6,59,6,56,4,59],42,2) + # connectivity + conn=DataArrayInt([8,0,1,2,3,4,5,6,7,8,1,8,9,2,10,11,12,5,8,3,2,13,14,6,15,16,17,8,2,9,18,13,12,19,20,15,8,21,22,23,24,25,26,27,28,8,22,29,30,23,31,32,33,26,8,24,23,34,35,27,36,37,38,8,23,30,39,34,33,40,41,36],72); + conn.setName(""); + connI=DataArrayInt([0,9,18,27,36,45,54,63,72],9) + m2=MEDCouplingUMesh.New("Mobile",2); + m2.setCoords(coords); + m2.setConnectivity(conn,connI,True); + # + m3,d1,d2=MEDCouplingUMesh.Intersect2DMeshes(m1,m2,1e-10); + self.assertEqual(105,m3.getNumberOfCells()); + self.assertEqual(105,d1.getNumberOfTuples()); + self.assertEqual(105,d2.getNumberOfTuples()); + self.assertEqual(704,m3.getNumberOfNodes()); + # + areaExpected=[-65.18804756198824,-65.18804756198824,-65.18804756198824,-65.18804756198824,-66.75884388878285,-66.75884388878285,-66.7588438887833,-66.75884388878308,-68.32964021557768,-68.32964021557768,-68.32964021557814,-68.32964021557791,-69.9004365423732,-69.9004365423732,-69.90043654237297,-69.90043654237297,-1.194568659706448,-1.0869994447159463,-142.2316939607081,-144.51326206513068,-144.5132620651309,-1.1945686597064424,-143.3186934054243,-5.002264310862817,-10.0261332846393,-3.9727823117092953,-7.290862524642649,-124.504404940456,-3.9727823117093237,-146.82366506060032,-150.79644737231024,-5.002264310862776,-145.79418306144626,-5.00208651738126,-10.054764051268958,-4.001067863263231,-8.027932154428669,-129.99378209314813,-4.001067863263216,-153.07856481622616,-157.0796326794898,-5.0020865173811915,-152.07754616210832,-5.001928880064381,-10.050590216368969,-4.00098721602491,-8.025810856794209,-136.28350081741684,-4.000987216024939,-159.36183077064402,-163.36281798667005,-5.0019288800643285,-158.36088910660442,-1.2991516319851801,-3.702636830195414,-3.7815130030068254,-6.265364371195623,-0.02516260900254963,-0.6553944641345026,-3.975752765070567,-7.368528340442765,-142.57249927881398,-0.02516260900254963,-3.9757527650706095,-165.64508791977525,-169.64600329384803,-1.299151631985167,-3.7026368301953885,-164.6442148316677,-10.00321285677458,-20.08414323176165,-8.001644468035863,-16.042954878437143,-304.0096070742277,-8.00164446803587,-350.1399180412005,-358.1415625092368,-10.003212856774468,-348.13834965246224,-3.794150313030109,-8.65049239704272,-0.02260276689354157,-0.5885167811200915,-370.2185414798688,-0.022602766893559393,-383.2517009710623,-383.2743037379555,-3.7941503130300576,-379.48015342492505,-408.40704496667513,-408.4070449666742,-408.4070449666742,-408.4070449666742,-433.53978619538975,-433.5397861953902,-433.5397861953911,-433.53978619539066,-458.67252742410983,-458.6725274241094,-458.67252742410983,-458.6725274241089,-608.6835766330232,-608.6835766330232,-608.6835766330232,-608.6835766330241] + expected1=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,16,17,18,19,19,20,20,20,20,20,21,21,22,23,23,24,24,24,24,24,25,25,26,27,27,28,28,28,28,28,29,29,30,31,31,32,32,32,32,32,32,32,32,32,33,33,33,34,35,35,35,36,36,36,36,36,37,37,38,39,39,40,40,40,40,40,41,41,42,43,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59] + expected2=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,2,-1,-1,-1,0,-1,0,2,4,5,-1,4,-1,-1,0,-1,0,2,4,5,-1,4,-1,-1,0,-1,0,2,4,5,-1,4,-1,-1,0,-1,0,1,2,3,4,5,6,7,-1,4,6,-1,-1,0,1,-1,1,3,6,7,-1,6,-1,-1,1,-1,1,3,6,7,-1,6,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1] + f3=m3.getMeasureField(ON_CELLS).getArray().getValues(); + for i in xrange(105): + self.assertAlmostEqual(areaExpected[i],f3[i],10) + pass + self.assertEqual(expected1,d1.getValues()) + self.assertEqual(expected2,d2.getValues()) + pass + + def testDAIBuildUnique1(self): + d=DataArrayInt([1,2,2,3,3,3,3,4,5,5,7,7,7,19]) + e=d.buildUnique() + self.assertTrue(e.isEqual(DataArrayInt([1,2,3,4,5,7,19]))) + pass + + def testDAIPartitionByDifferentValues1(self): + d=DataArrayInt([1,0,1,2,0,2,2,-3,2]) + expected=[[-3,[7]],[0,[1,4]],[1,[0,2]],[2,[3,5,6,8]]] + for i,elt in enumerate(zip(*d.partitionByDifferentValues())): + self.assertEqual(expected[i][0],elt[1]) + self.assertEqual(expected[i][1],elt[0].getValues()) + pass + pass + + def testFieldGaussMultiDiscPerType1(self): + coords=DataArrayDouble([0.,0.,0.,1.,1.,1.,1.,0.,0.,0.5,0.5,1.,1.,0.5,0.5,0.],8,2) + mQ8=MEDCouplingUMesh("",2) ; mQ8.setCoords(coords) + mQ8.allocateCells(1) + mQ8.insertNextCell(NORM_QUAD8,range(8)) + mQ8.finishInsertingCells() + mQ4=MEDCouplingUMesh("",2) ; mQ4.setCoords(coords) + mQ4.allocateCells(1) + mQ4.insertNextCell(NORM_QUAD4,range(4)) + mQ4.finishInsertingCells() + mT3=MEDCouplingUMesh("",2) ; mT3.setCoords(coords) + mT3.allocateCells(1) + mT3.insertNextCell(NORM_TRI3,range(3)) + mT3.finishInsertingCells() + + tr=[[0.,0.],[2.,0.], [0.,2.],[2.,2.],[4.,2.],[6.,2.],[8.,2.],[10.,2.],[12.,2.],[0.,4.],[2.,4.],[4.,4.],[6.,4.],[8.,4.],[10.,4.],[12.,4.],[14.,4.],[16.,4.],[18.,4.],[20.,4.],[22.,4.]] + ms=2*[mQ4]+7*[mQ8]+11*[mT3] + ms[:]=(elt.deepCpy() for elt in ms) + for m,t in zip(ms,tr): + d=m.getCoords() ; d+= t + pass + m=MEDCouplingUMesh.MergeUMeshes(ms) + f=MEDCouplingFieldDouble.New(ON_GAUSS_PT,NO_TIME) + f.setMesh(m) + # throw because cell 0,1 are QUAD4 and cell 3 is QUAD8 + self.assertRaises(InterpKernelException,f.setGaussLocalizationOnCells,[0,1,3],[0.,0.,1.,0.,1.,1.,0.,1.],[0.3,0.3,0.7,0.7],[0.8,0.2]) + f.setGaussLocalizationOnCells([0,1],[0.,0.,1.,0.,1.,1.,0.,1.],[0.3,0.3,0.7,0.7],[0.8,0.2]) + f.setGaussLocalizationOnCells([3,2,5],[0.,0.,1.,0.,1.,1.,0.,1.,0.5,0.,1.,0.5,0.5,1.,0.,0.5],[0.3,0.3,0.7,0.7,0.9,0.9],[0.8,0.05,0.15]) + f.setGaussLocalizationOnCells([4,6,8,7],[0.,0.,1.,0.,1.,1.,0.,1.,0.5,0.,1.,0.5,0.5,1.,0.,0.5],[0.3,0.3,0.7,0.7,0.9,0.9,-0.1,0.3],[0.7,0.05,0.15,0.1]) + f.setGaussLocalizationOnCells([9,10,11,12,13],[0.,0.,1.,0.,1.,1.],[0.4,0.4],[1.]) + f.setGaussLocalizationOnCells([14,15,16,17,18,19],[0.,0.,1.,0.,1.,1.],[0.4,0.4,0.14,0.16],[0.22,0.78]) + self.assertEqual(46,f.getNumberOfTuplesExpected()) + vals=DataArrayDouble.New(46*3,1) ; vals.iota(7.7) ; vals.rearrange(3) + f.setArray(vals) + f.checkCoherency() + #f.getLocalizationOfDiscr() + self.assertRaises(InterpKernelException,f.getGaussLocalizationIdOfOneType,NORM_QUAD8) #throw because several loc + self.assertEqual([1,2],f.getGaussLocalizationIdsOfOneType(NORM_QUAD8)) + self.assertEqual([0,0,1,1,2,1,2,2,2,3,3,3,3,3,4,4,4,4,4,4],f.getDiscretization().getArrayOfDiscIds().getValues()) + fc=f[[1,2,3,8]] + fc.checkCoherency() + self.assertTrue(DataArrayDouble([13.7,14.7,15.7,16.7,17.7,18.7,19.7,20.7,21.7,22.7,23.7,24.7,25.7,26.7,27.7,28.7,29.7,30.7,31.7,32.7,33.7,34.7,35.7,36.7,82.7,83.7,84.7,85.7,86.7,87.7,88.7,89.7,90.7,91.7,92.7,93.7],12,3).isEqual(fc.getArray(),1e-10)) + fc.renumberCells([3,2,0,1]) + self.assertTrue(DataArrayDouble([28.7, 29.7, 30.7, 31.7, 32.7, 33.7, 34.7, 35.7, 36.7, 82.7, 83.7, 84.7, 85.7, 86.7, 87.7, 88.7, 89.7, 90.7, 91.7, 92.7, 93.7, 19.7, 20.7, 21.7, 22.7, 23.7, 24.7, 25.7, 26.7, 27.7, 13.7, 14.7, 15.7, 16.7, 17.7, 18.7],12,3).isEqual(fc.getArray(),1e-10)) + fc.getArray() + pass + + def testSwigRotate(self): + d=DataArrayDouble([1.,2.,3.,4.,6.,5.],2,3) + MEDCouplingPointSet.Rotate3DAlg([0.,0.,0.],[0.,1.,0.],1.5707963267948966,d) + self.assertTrue(d.isEqual(DataArrayDouble([3.,2.,-1.,5.,6.,-4.],2,3),1e-12)) + d=DataArrayDouble([1.,2.,3.,4.,6.,5.],3,2) + MEDCouplingPointSet.Rotate2DAlg([0.,0.],1.5707963267948966,d) + self.assertTrue(d.isEqual(DataArrayDouble([-2.,1.,-4.,3.,-5.,6.],3,2),1e-12)) + pass + + def testSwigCMeshProtection(self): + cm=MEDCouplingCMesh() + self.assertRaises(InterpKernelException,cm.setCoordsAt,0,DataArrayDouble([4.,4.5,6.,7.],2,2)) + self.assertRaises(InterpKernelException,cm.setCoords,DataArrayDouble([4.,4.5,6.,7.],2,2)) + pass + + def testSwigCellsInBoundingBox1(self): + m3D=MEDCouplingDataForTest.build3DExtrudedUMesh_1()[0] + self.assertTrue(m3D.getCellsInBoundingBox([(0,3),(0,3),(0,1)],-1e-12).isEqual(DataArrayInt([0,1,2,3,4,5]))) + self.assertRaises(InterpKernelException,m3D.getCellsInBoundingBox,[(0,3,0),(3,0,1)],-1e-12) + pass + def setUp(self): pass pass diff --git a/src/MEDCoupling_Swig/MEDCouplingCommon.i b/src/MEDCoupling_Swig/MEDCouplingCommon.i index 804712b87..dabb52f2a 100644 --- a/src/MEDCoupling_Swig/MEDCouplingCommon.i +++ b/src/MEDCoupling_Swig/MEDCouplingCommon.i @@ -78,6 +78,8 @@ using namespace INTERP_KERNEL; %feature("docstring"); %newobject ParaMEDMEM::MEDCouplingFieldDiscretization::getOffsetArr; +%newobject ParaMEDMEM::MEDCouplingFieldDiscretization::clone; +%newobject ParaMEDMEM::MEDCouplingFieldDiscretization::clonePart; %newobject ParaMEDMEM::MEDCouplingField::buildMeasureField; %newobject ParaMEDMEM::MEDCouplingField::getLocalizationOfDiscr; %newobject ParaMEDMEM::MEDCouplingField::computeTupleIdsToSelectFromCellIds; @@ -162,6 +164,7 @@ using namespace INTERP_KERNEL; %newobject ParaMEDMEM::DataArrayInt::buildUnion; %newobject ParaMEDMEM::DataArrayInt::buildSubstraction; %newobject ParaMEDMEM::DataArrayInt::buildIntersection; +%newobject ParaMEDMEM::DataArrayInt::buildUnique; %newobject ParaMEDMEM::DataArrayInt::deltaShiftIndex; %newobject ParaMEDMEM::DataArrayInt::buildExplicitArrByRanges; %newobject ParaMEDMEM::DataArrayInt::findRangeIdForEachTuple; @@ -440,6 +443,7 @@ namespace ParaMEDMEM virtual DataArrayInt *simplexize(int policy) throw(INTERP_KERNEL::Exception); static MEDCouplingMesh *MergeMeshes(const MEDCouplingMesh *mesh1, const MEDCouplingMesh *mesh2) throw(INTERP_KERNEL::Exception); static int GetDimensionOfGeometricType(INTERP_KERNEL::NormalizedCellType type) throw(INTERP_KERNEL::Exception); + static const char *GetReprOfGeometricType(INTERP_KERNEL::NormalizedCellType type) throw(INTERP_KERNEL::Exception); %extend { std::string __str__() const @@ -845,10 +849,53 @@ namespace ParaMEDMEM std::set ret=self->getDifferentValues(); return convertIntArrToPyList3(ret); } + + PyObject *partitionByDifferentValues() const throw(INTERP_KERNEL::Exception) + { + std::vector ret1; + std::vector ret0=self->partitionByDifferentValues(ret1); + std::size_t sz=ret0.size(); + PyObject *pyRet=PyTuple_New(2); + PyObject *pyRet0=PyList_New((int)sz); + PyObject *pyRet1=PyList_New((int)sz); + for(std::size_t i=0;i val2; + const int *inp=convertObjToPossibleCpp1_Safe(li,sw,sz,val1,val2); + return self->clonePart(inp,inp+sz); + } +} + +%extend ParaMEDMEM::MEDCouplingFieldDiscretizationPerCell +{ + PyObject *getArrayOfDiscIds() const + { + DataArrayInt *ret=const_cast(self->getArrayOfDiscIds()); + if(ret) + ret->incrRef(); + return SWIG_NewPointerObj(SWIG_as_voidptr(ret),SWIGTYPE_p_ParaMEDMEM__DataArrayInt, SWIG_POINTER_OWN | 0 ); + } } %ignore ParaMEDMEM::DataArray::getInfoOnComponents; %ignore ParaMEDMEM::DataArrayInt::getDifferentValues; +%ignore ParaMEDMEM::DataArrayInt::partitionByDifferentValues; +%ignore ParaMEDMEM::MEDCouplingFieldDiscretizationPerCell::getArrayOfDiscIds; +%ignore ParaMEDMEM::MEDCouplingFieldDiscretization::clonePart; %include "MEDCouplingMemArray.hxx" %include "NormalizedUnstructuredMesh.hxx" @@ -1202,16 +1249,46 @@ namespace ParaMEDMEM for(int i=0;i c=convertPyToNewDblArr2(center,&sz); + int sw,nbNodes=0; + double val0; ParaMEDMEM::DataArrayDouble *val1=0; ParaMEDMEM::DataArrayDoubleTuple *val2=0; + std::vector val3; + const double *coo=convertObjToPossibleCpp5_Safe2(coords,sw,val0,val1,val2,val3, + "Rotate2DAlg",2,true,nbNodes); + if(sw!=2 && sw!=3) + throw INTERP_KERNEL::Exception("Invalid call to MEDCouplingPointSet::Rotate2DAlg : try another overload method !"); + ParaMEDMEM::MEDCouplingPointSet::Rotate2DAlg(c,angle,nbNodes,const_cast(coo)); + } + static void Rotate3DAlg(PyObject *center, PyObject *vect, double angle, int nbNodes, PyObject *coords) throw(INTERP_KERNEL::Exception) { int sz,sz2; INTERP_KERNEL::AutoPtr c=convertPyToNewDblArr2(center,&sz); INTERP_KERNEL::AutoPtr coo=convertPyToNewDblArr2(coords,&sz); - double *v=convertPyToNewDblArr2(vect,&sz2); + INTERP_KERNEL::AutoPtr v=convertPyToNewDblArr2(vect,&sz2); ParaMEDMEM::MEDCouplingPointSet::Rotate3DAlg(c,v,angle,nbNodes,coo); for(int i=0;i c=convertPyToNewDblArr2(center,&sz); + int sw,nbNodes=0; + double val0; ParaMEDMEM::DataArrayDouble *val1=0; ParaMEDMEM::DataArrayDoubleTuple *val2=0; + std::vector val3; + const double *coo=convertObjToPossibleCpp5_Safe2(coords,sw,val0,val1,val2,val3, + "Rotate3DAlg",3,true,nbNodes); + if(sw!=2 && sw!=3) + throw INTERP_KERNEL::Exception("Invalid call to MEDCouplingPointSet::Rotate3DAlg : try another overload method !"); + INTERP_KERNEL::AutoPtr v=convertPyToNewDblArr2(vect,&sz2); + ParaMEDMEM::MEDCouplingPointSet::Rotate3DAlg(c,v,angle,nbNodes,const_cast(coo)); + } } }; @@ -1353,6 +1430,7 @@ namespace ParaMEDMEM MEDCouplingFieldDouble *getWarpField() const throw(INTERP_KERNEL::Exception); MEDCouplingFieldDouble *getSkewField() const throw(INTERP_KERNEL::Exception); DataArrayInt *convexEnvelop2D() throw(INTERP_KERNEL::Exception); + std::string cppRepr() const throw(INTERP_KERNEL::Exception); static MEDCouplingUMesh *Build0DMeshFromCoords(DataArrayDouble *da) throw(INTERP_KERNEL::Exception); static MEDCouplingUMesh *MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) throw(INTERP_KERNEL::Exception); static MEDCouplingUMesh *MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) throw(INTERP_KERNEL::Exception); @@ -2721,10 +2799,8 @@ namespace ParaMEDMEM if(nbOfCompo<0) throw INTERP_KERNEL::Exception("DataArrayDouble::New : should be a positive number of components !"); MEDCouplingAutoRefCountObjectPtr ret=DataArrayDouble::New(); - double *tmp=new double[nbOfTuples*nbOfCompo]; - try { fillArrayWithPyListDbl(elt0,tmp,nbOfTuples*nbOfCompo,0.,true); } - catch(INTERP_KERNEL::Exception& e) { delete [] tmp; throw e; } - ret->useArray(tmp,true,CPP_DEALLOC,nbOfTuples,nbOfCompo); + std::vector tmp=fillArrayWithPyListDbl2(elt0,nbOfTuples,nbOfCompo); + ret->alloc(nbOfTuples,nbOfCompo); std::copy(tmp.begin(),tmp.end(),ret->getPointer()); ret->incrRef(); return ret; } @@ -2734,10 +2810,9 @@ namespace ParaMEDMEM else {//DataArrayDouble.New([1.,3.,4.],3) MEDCouplingAutoRefCountObjectPtr ret=DataArrayDouble::New(); - double *tmp=new double[nbOfTuples]; - try { fillArrayWithPyListDbl(elt0,tmp,nbOfTuples,0.,true); } - catch(INTERP_KERNEL::Exception& e) { delete [] tmp; throw e; } - ret->useArray(tmp,true,CPP_DEALLOC,nbOfTuples,1); + int tmpp1=-1; + std::vector tmp=fillArrayWithPyListDbl2(elt0,nbOfTuples,tmpp1); + ret->alloc(nbOfTuples,tmpp1); std::copy(tmp.begin(),tmp.end(),ret->getPointer()); ret->incrRef(); return ret; } @@ -2747,16 +2822,10 @@ namespace ParaMEDMEM } else {// DataArrayDouble.New([1.,3.,4.]) - int szz=-1; - if(PyList_Check(elt0)) - szz=PyList_Size(elt0); - else - szz=PyTuple_Size(elt0); MEDCouplingAutoRefCountObjectPtr ret=DataArrayDouble::New(); - double *tmp=new double[szz]; - try { fillArrayWithPyListDbl(elt0,tmp,szz,0.,true); } - catch(INTERP_KERNEL::Exception& e) { delete [] tmp; throw e; } - ret->useArray(tmp,true,CPP_DEALLOC,szz,1); + int tmpp1=-1,tmpp2=-1; + std::vector tmp=fillArrayWithPyListDbl2(elt0,tmpp1,tmpp2); + ret->alloc(tmpp1,tmpp2); std::copy(tmp.begin(),tmp.end(),ret->getPointer()); ret->incrRef(); return ret; } @@ -4441,10 +4510,8 @@ namespace ParaMEDMEM if(nbOfCompo<0) throw INTERP_KERNEL::Exception("DataArrayInt::New : should be a positive number of components !"); MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); - int *tmp=new int[nbOfTuples*nbOfCompo]; - try { fillArrayWithPyListInt(elt0,tmp,nbOfTuples*nbOfCompo,0,true); } - catch(INTERP_KERNEL::Exception& e) { delete [] tmp; throw e; } - ret->useArray(tmp,true,CPP_DEALLOC,nbOfTuples,nbOfCompo); + std::vector tmp=fillArrayWithPyListInt2(elt0,nbOfTuples,nbOfCompo); + ret->alloc(nbOfTuples,nbOfCompo); std::copy(tmp.begin(),tmp.end(),ret->getPointer()); ret->incrRef(); return ret; } @@ -4454,10 +4521,9 @@ namespace ParaMEDMEM else {//DataArrayInt.New([1,3,4],3) MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); - int *tmp=new int[nbOfTuples]; - try { fillArrayWithPyListInt(elt0,tmp,nbOfTuples,0,true); } - catch(INTERP_KERNEL::Exception& e) { delete [] tmp; throw e; } - ret->useArray(tmp,true,CPP_DEALLOC,nbOfTuples,1); + int tmpp1=-1; + std::vector tmp=fillArrayWithPyListInt2(elt0,nbOfTuples,tmpp1); + ret->alloc(nbOfTuples,tmpp1); std::copy(tmp.begin(),tmp.end(),ret->getPointer()); ret->incrRef(); return ret; } @@ -4467,16 +4533,10 @@ namespace ParaMEDMEM } else {// DataArrayInt.New([1,3,4]) - int szz=-1; - if(PyList_Check(elt0)) - szz=PyList_Size(elt0); - else - szz=PyTuple_Size(elt0); MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); - int *tmp=new int[szz]; - try { fillArrayWithPyListInt(elt0,tmp,szz,0,true); } - catch(INTERP_KERNEL::Exception& e) { delete [] tmp; throw e; } - ret->useArray(tmp,true,CPP_DEALLOC,szz,1); + int tmpp1=-1,tmpp2=-1; + std::vector tmp=fillArrayWithPyListInt2(elt0,tmpp1,tmpp2); + ret->alloc(tmpp1,tmpp2); std::copy(tmp.begin(),tmp.end(),ret->getPointer()); ret->incrRef(); return ret; } @@ -6161,6 +6221,8 @@ namespace ParaMEDMEM int getNbOfGaussLocalization() const throw(INTERP_KERNEL::Exception); int getGaussLocalizationIdOfOneCell(int cellId) const throw(INTERP_KERNEL::Exception); const MEDCouplingGaussLocalization& getGaussLocalization(int locId) const throw(INTERP_KERNEL::Exception); + int getGaussLocalizationIdOfOneType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception); + void setDiscretization(MEDCouplingFieldDiscretization *newDisc); %extend { PyObject *getMesh() const throw(INTERP_KERNEL::Exception) { @@ -6178,6 +6240,12 @@ namespace ParaMEDMEM return convertFieldDiscretization(ret,SWIG_POINTER_OWN | 0 ); } + PyObject *getGaussLocalizationIdsOfOneType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception) + { + std::set ret=self->getGaussLocalizationIdsOfOneType(type); + return convertIntArrToPyList3(ret); + } + PyObject *isEqualIfNotWhy(const MEDCouplingField *other, double meshPrec, double valsPrec) const throw(INTERP_KERNEL::Exception) { std::string ret1; diff --git a/src/MEDCoupling_Swig/MEDCouplingRemapperTest.py b/src/MEDCoupling_Swig/MEDCouplingRemapperTest.py index 1e7727e3f..5c8042f5e 100644 --- a/src/MEDCoupling_Swig/MEDCouplingRemapperTest.py +++ b/src/MEDCoupling_Swig/MEDCouplingRemapperTest.py @@ -122,6 +122,169 @@ class MEDCouplingBasicsTest(unittest.TestCase): self.assertAlmostEqual(valuesExpected[i0],values[i0],12); pass pass + + def testPrepareUC(self): + # 1D + coords=DataArrayDouble([0.,0.5,0.7]) + src=MEDCouplingUMesh("",1) ; src.setCoords(coords) + src.allocateCells(2) ; src.insertNextCell(NORM_SEG2,[0,1]) ; src.insertNextCell(NORM_SEG2,[1,2]) ; src.finishInsertingCells() + trg=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.7,-0.1,0.2,0.7,2.,2.3]) + trg.setCoordsAt(0,arr) + fieldSrc=MEDCouplingFieldDouble(ON_CELLS,NO_TIME) ; fieldSrc.setMesh(src) ; arrSrc=DataArrayDouble([10.,30.]) + fieldSrc.setNature(Integral) ; fieldSrc.setArray(arrSrc) + rem=MEDCouplingRemapper() + rem.prepare(src,trg,"P0P0") + trgField=rem.transferField(fieldSrc,-7.) + expected1=[-7.,4.,36.,-7.,-7.] + self.assertEqual(5,trgField.getArray().getNumberOfTuples()) + self.assertEqual(5,len(expected1)) + for i,val in enumerate(expected1): + self.assertAlmostEqual(expected1[i],trgField.getArray().getIJ(i,0),12); + pass + # 2D + coords=DataArrayDouble([0.,0.,0.,1.,1.,1.,1.,0.,0.5,-0.2],5,2) + src=MEDCouplingUMesh("",2) ; src.setCoords(coords) + src.allocateCells(2) ; src.insertNextCell(NORM_TRI3,[0,1,2]) ; src.insertNextCell(NORM_TRI3,[3,4,0]) ; src.finishInsertingCells() + trg=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.7,-0.1,0.2,0.7,2.,2.3]) + trg.setCoordsAt(0,arr) ; trg.setCoordsAt(1,arr) + fieldSrc=MEDCouplingFieldDouble(ON_CELLS,NO_TIME) ; fieldSrc.setMesh(src) ; arrSrc=DataArrayDouble([10.,30.]) + fieldSrc.setNature(Integral) ; fieldSrc.setArray(arrSrc) + rem=MEDCouplingRemapper() + rem.prepare(src,trg,"P0P0") + trgField=rem.transferField(fieldSrc,-7.) + expected2=[-7.,-7.,7.35,0.15,-7.,-7.,2.8,14.85,5.25,-7.,-7.,2.,2.5,-7.,-7.,-7.,1.2,3.,0.9,-7.,-7.,-7.,-7.,-7.,-7.] + self.assertEqual(25,trgField.getArray().getNumberOfTuples()) + self.assertEqual(25,len(expected2)) + for i,val in enumerate(expected2): + self.assertAlmostEqual(expected2[i],trgField.getArray().getIJ(i,0),12); + pass + # 3D + coords=DataArrayDouble([0.,0.,0.,0.,1.,0.,1.,1.,0.,1.,0.,0.,0.5,-0.2,0.,0.1,0.8,1.,0.5,0.,1.],7,3) + src=MEDCouplingUMesh("",3) ; src.setCoords(coords) + src.allocateCells(2) ; src.insertNextCell(NORM_TETRA4,[0,1,2,5]) ; src.insertNextCell(NORM_TETRA4,[3,4,0,6]) ; src.finishInsertingCells() + trg=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.7,-0.1,0.2,0.7,2.,2.3]) ; arr2=DataArrayDouble([-0.7,0.2,0.6,1.2,2.]) + trg.setCoordsAt(0,arr) ; trg.setCoordsAt(1,arr) ; trg.setCoordsAt(2,arr2) + src.checkCoherency2(1e-10) + trg.checkCoherency() + fieldSrc=MEDCouplingFieldDouble(ON_CELLS,NO_TIME) ; fieldSrc.setMesh(src) ; arrSrc=DataArrayDouble([10.,30.]) + fieldSrc.setNature(Integral) ; fieldSrc.setArray(arrSrc) + rem=MEDCouplingRemapper() + rem.prepare(src,trg,"P0P0") + trgField=rem.transferField(fieldSrc,-7.) + expected3=[-7.,-7.,2.925,0.015,-7.,-7.,0.9392,8.595,2.265,-7.,-7.,1.1008,1.1192,-7.,-7.,-7.,0.6392,1.6408,0.2808,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,0.81,-7.,-7.,-7.,0.1208,11.55,0.96,-7.,-7.,1.1752,0.6592,-7.,-7.,-7.,0.8512,1.7744,0.0192,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,1.92,-7.,-7.,-7.,0.12578571428571422,0.007314285714285673,-7.,-7.,-7.,0.3189253968253971,0.1879746031746033,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.,-7.] + self.assertEqual(100,trgField.getArray().getNumberOfTuples()) + self.assertEqual(100,len(expected3)) + for i,val in enumerate(expected3): + self.assertAlmostEqual(expected3[i],trgField.getArray().getIJ(i,0),12); + pass + pass + + def testPrepareCU(self): + # 1D + coords=DataArrayDouble([0.,0.5,0.7]) + trg=MEDCouplingUMesh("",1) ; trg.setCoords(coords) + trg.allocateCells(2) ; trg.insertNextCell(NORM_SEG2,[0,1]) ; trg.insertNextCell(NORM_SEG2,[1,2]) ; trg.finishInsertingCells() + src=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.7,-0.1,0.2,0.7,2.,2.3]) + src.setCoordsAt(0,arr) + fieldSrc=MEDCouplingFieldDouble(ON_CELLS,NO_TIME) ; fieldSrc.setMesh(src) ; arrTrg=DataArrayDouble([10.,30.,40.,70.,80.]) + fieldSrc.setNature(Integral) ; fieldSrc.setArray(arrTrg) + rem=MEDCouplingRemapper() + rem.prepare(src,trg,"P0P0") + trgField=rem.transferField(fieldSrc,-7.) + expected1=[44.,16.] + self.assertEqual(2.,trgField.getArray().getNumberOfTuples()) + self.assertEqual(2,len(expected1)) + for i,val in enumerate(expected1): + self.assertAlmostEqual(expected1[i],trgField.getArray().getIJ(i,0),12); + pass + # 2D + coords=DataArrayDouble([0.,0.,0.,1.,1.,1.,1.,0.,0.5,-0.2],5,2) + trg=MEDCouplingUMesh("",2) ; trg.setCoords(coords) + trg.allocateCells(2) ; trg.insertNextCell(NORM_TRI3,[0,1,2]) ; trg.insertNextCell(NORM_TRI3,[3,4,0]) ; trg.finishInsertingCells() + src=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.7,-0.1,0.2,0.7,2.,2.3]) + src.setCoordsAt(0,arr) ; src.setCoordsAt(1,arr) + fieldSrc=MEDCouplingFieldDouble(ON_CELLS,NO_TIME) ; fieldSrc.setMesh(src) ; arrSrc=DataArrayDouble([10.,30.,40.,70.,80.,110.,130.,140.,170.,180.,210.,230.,240.,270.,280.,310.,330.,340.,370.,380.,410.,430.,440.,470.,480.]) + fieldSrc.setNature(Integral) ; fieldSrc.setArray(arrSrc) + rem=MEDCouplingRemapper() + rem.prepare(src,trg,"P0P0") + trgField=rem.transferField(fieldSrc,-7.) + expected2=[441.3050624589086,68.69529914529915] + self.assertEqual(2,trgField.getArray().getNumberOfTuples()) + self.assertEqual(2,len(expected2)) + for i,val in enumerate(expected2): + self.assertAlmostEqual(expected2[i],trgField.getArray().getIJ(i,0),12); + pass + # 3D + coords=DataArrayDouble([0.,0.,0.,0.,1.,0.,1.,1.,0.,1.,0.,0.,0.5,-0.2,0.,0.1,0.8,1.,0.5,0.,1.],7,3) + trg=MEDCouplingUMesh("",3) ; trg.setCoords(coords) + trg.allocateCells(2) ; trg.insertNextCell(NORM_TETRA4,[0,1,2,5]) ; trg.insertNextCell(NORM_TETRA4,[3,4,0,6]) ; trg.finishInsertingCells() + src=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.7,-0.1,0.2,0.7,2.,2.3]) ; arr2=DataArrayDouble([-0.7,0.2,0.6,1.2,2.]) + src.setCoordsAt(0,arr) ; src.setCoordsAt(1,arr) ; src.setCoordsAt(2,arr2) + trg.checkCoherency2(1e-10) + src.checkCoherency() + fieldSrc=MEDCouplingFieldDouble(ON_CELLS,NO_TIME) ; fieldSrc.setMesh(src) ; arrSrc=DataArrayDouble(100) ; arrSrc.iota(7.7) + fieldSrc.setNature(Integral) ; fieldSrc.setArray(arrSrc) + rem=MEDCouplingRemapper() + rem.prepare(src,trg,"P0P0") + trgField=rem.transferField(fieldSrc,-7.) + expected3=[39.635196634558845,12.13422356758468] + self.assertEqual(2,trgField.getArray().getNumberOfTuples()) + self.assertEqual(2,len(expected3)) + for i,val in enumerate(expected3): + self.assertAlmostEqual(expected3[i],trgField.getArray().getIJ(i,0),12); + pass + pass + + def testPrepareCC(self): + # 1D + src=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.7,-0.1,0.2,0.7,2.,2.3]) + src.setCoordsAt(0,arr) + trg=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.9,-0.1,0.15]) + trg.setCoordsAt(0,arr) + fieldSrc=MEDCouplingFieldDouble(ON_CELLS,NO_TIME) ; fieldSrc.setMesh(src) ; arrTrg=DataArrayDouble([10.,30.,40.,70.,80.]) + fieldSrc.setNature(Integral) ; fieldSrc.setArray(arrTrg) + rem=MEDCouplingRemapper() + rem.prepare(src,trg,"P0P0") + trgField=rem.transferField(fieldSrc,-7.) + expected1=[10.,25.] + self.assertEqual(2.,trgField.getArray().getNumberOfTuples()) + self.assertEqual(2,len(expected1)) + for i,val in enumerate(expected1): + self.assertAlmostEqual(expected1[i],trgField.getArray().getIJ(i,0),12); + pass + # 2D + src=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.7,-0.1,0.2,0.7,2.,2.3]) + src.setCoordsAt(0,arr) ; src.setCoordsAt(1,arr) + trg=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.9,-0.1,0.15]) + trg.setCoordsAt(0,arr) ; trg.setCoordsAt(1,arr) + fieldSrc=MEDCouplingFieldDouble(ON_CELLS,NO_TIME) ; fieldSrc.setMesh(src) ; arrSrc=DataArrayDouble([10.,30.,40.,70.,80.,110.,130.,140.,170.,180.,210.,230.,240.,270.,280.,310.,330.,340.,370.,380.,410.,430.,440.,470.,480.]) + fieldSrc.setNature(Integral) ; fieldSrc.setArray(arrSrc) + rem=MEDCouplingRemapper() + rem.prepare(src,trg,"P0P0") + trgField=rem.transferField(fieldSrc,-7.) + expected2=[10.,25.,91.66666666666666,90.27777777777777] + self.assertEqual(4,trgField.getArray().getNumberOfTuples()) + self.assertEqual(4,len(expected2)) + for i,val in enumerate(expected2): + self.assertAlmostEqual(expected2[i],trgField.getArray().getIJ(i,0),12); + pass + # 3D + src=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.7,-0.1,0.2,0.7,2.,2.3]) + src.setCoordsAt(0,arr) ; src.setCoordsAt(1,arr) ; src.setCoordsAt(2,arr) + trg=MEDCouplingCMesh() ; arr=DataArrayDouble([-0.9,-0.1,0.15]) + trg.setCoordsAt(0,arr) ; trg.setCoordsAt(1,arr) ; trg.setCoordsAt(2,arr) + fieldSrc=MEDCouplingFieldDouble(ON_CELLS,NO_TIME) ; fieldSrc.setMesh(src) ; arrSrc=DataArrayDouble(125) ; arrSrc.iota(7.7) + fieldSrc.setNature(Integral) ; fieldSrc.setArray(arrSrc) ; fieldSrc.checkCoherency() + rem=MEDCouplingRemapper() + rem.prepare(src,trg,"P0P0") + trgField=rem.transferField(fieldSrc,-7.) + expected3=[7.7, 7.249999999999999, 10.583333333333332, 9.513888888888886, 27.25, 23.40277777777777, 26.180555555555546, 22.39583333333333] + self.assertEqual(8,trgField.getArray().getNumberOfTuples()) + self.assertEqual(8,len(expected3)) + for i,val in enumerate(expected3): + self.assertAlmostEqual(expected3[i],trgField.getArray().getIJ(i,0),12); + pass + pass def build2DSourceMesh_1(self): sourceCoords=[-0.3,-0.3, 0.7,-0.3, -0.3,0.7, 0.7,0.7] diff --git a/src/MEDCoupling_Swig/MEDCouplingTypemaps.i b/src/MEDCoupling_Swig/MEDCouplingTypemaps.i index 98aad204d..c16812429 100644 --- a/src/MEDCoupling_Swig/MEDCouplingTypemaps.i +++ b/src/MEDCoupling_Swig/MEDCouplingTypemaps.i @@ -346,7 +346,133 @@ static void convertPyToNewIntArr4(PyObject *pyLi, int recurseLev, int nbOfSubPar throw INTERP_KERNEL::Exception("convertPyToNewIntArr4 : not a list nor a tuple recursively !"); } +static void checkFillArrayWithPyList(int size1, int size2, int& nbOfTuples, int& nbOfComp) throw(INTERP_KERNEL::Exception) +{ + if(nbOfTuples==-1) + { + if(nbOfComp==-1) { nbOfTuples=size1; nbOfComp=size2; } + else { if(nbOfComp==size2) { nbOfTuples=size1; } else + { + std::ostringstream oss; oss << "fillArrayWithPyListDbl2 : mismatch between nb of elemts : Input has " << size1 << " tuples and " << size2 << " components"; + oss << " whereas nb of components expected is " << nbOfComp << " !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } } + } + else + { + if(nbOfComp!=-1) + { + if((nbOfTuples!=size1 || nbOfComp!=size2)) + { + if(size2!=1 || size1!=nbOfComp*nbOfTuples) + { + std::ostringstream oss; oss << "fillArrayWithPyListDbl2 : mismatch between nb of elemts : Input has " << size1 << " tuples and " << size2 << " components"; + oss << " whereas nb of tuples expected is " << nbOfTuples << " and number of components expected is " << nbOfComp << " !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + } + else + { + if(nbOfTuples==size1) + nbOfComp=size2; + else + { + std::ostringstream oss; oss << "fillArrayWithPyListDbl2 : mismatch between nb of elemts : Input has " << size1 << " tuples and " << size2 << " components"; + oss << " whereas nb of tuples expected is " << nbOfTuples << " !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + } +} + +static void fillArrayWithPyListInt3(PyObject *pyLi, int& nbOfElt, std::vector& ret) +{ + static const char MSG[]="fillArrayWithPyListInt3 : It appears that the input list or tuple is composed by elts having different sizes !"; + if(PyInt_Check(pyLi)) + { + long val=PyInt_AS_LONG(pyLi); + if(nbOfElt==-1) + nbOfElt=1; + else + if(nbOfElt!=1) + throw INTERP_KERNEL::Exception(MSG); + ret.push_back(val); + } + else if(PyList_Check(pyLi)) + { + int size=PyList_Size(pyLi); + int tmp=0; + for(int i=0;i fillArrayWithPyListInt2(PyObject *pyLi, int& nbOfTuples, int& nbOfComp) throw(INTERP_KERNEL::Exception) +{ + std::vector ret; + int size1=-1,size2=-1; + if(PyList_Check(pyLi)) + { + size1=PyList_Size(pyLi); + for(int i=0;i fillArrayWithPyListInt2 + */ static void fillArrayWithPyListInt(PyObject *pyLi, int *arrToFill, int sizeOfArray, int dftVal, bool chckSize) throw(INTERP_KERNEL::Exception) { if(PyList_Check(pyLi)) @@ -492,6 +618,104 @@ static double *convertPyToNewDblArr2(PyObject *pyLi, int *size) throw(INTERP_KER throw INTERP_KERNEL::Exception("convertPyToNewDblArr2 : not a list"); } +static void fillArrayWithPyListDbl3(PyObject *pyLi, int& nbOfElt, std::vector& ret) +{ + static const char MSG[]="fillArrayWithPyListDbl3 : It appears that the input list or tuple is composed by elts having different sizes !"; + if(PyFloat_Check(pyLi)) + { + if(nbOfElt==-1) + nbOfElt=1; + else + if(nbOfElt!=1) + throw INTERP_KERNEL::Exception(MSG); + double val=PyFloat_AS_DOUBLE(pyLi); + ret.push_back(val); + } + else if(PyInt_Check(pyLi)) + { + long val0=PyInt_AS_LONG(pyLi); + double val=val0; + if(nbOfElt==-1) + nbOfElt=1; + else + if(nbOfElt!=1) + throw INTERP_KERNEL::Exception(MSG); + ret.push_back(val); + } + else if(PyList_Check(pyLi)) + { + int size=PyList_Size(pyLi); + int tmp=0; + for(int i=0;i fillArrayWithPyListDbl2(PyObject *pyLi, int& nbOfTuples, int& nbOfComp) throw(INTERP_KERNEL::Exception) +{ + std::vector ret; + int size1=-1,size2=-1; + if(PyList_Check(pyLi)) + { + size1=PyList_Size(pyLi); + for(int i=0;i fillArrayWithPyListDbl2 + */ static void fillArrayWithPyListDbl(PyObject *pyLi, double *arrToFill, int sizeOfArray, double dftVal, bool chckSize) throw(INTERP_KERNEL::Exception) { if(PyList_Check(pyLi)) @@ -557,7 +781,7 @@ static void fillArrayWithPyListDbl(PyObject *pyLi, double *arrToFill, int sizeOf return ; } else - throw INTERP_KERNEL::Exception("convertPyToNewIntArr : not a list"); + throw INTERP_KERNEL::Exception("fillArrayWithPyListDbl : not a list nor a tuple"); } //convertFromPyObjVectorOfObj(pyLi,SWIGTYPE_p_ParaMEDMEM__MEDCouplingUMesh,"MEDCouplingUMesh") @@ -586,7 +810,6 @@ static void convertFromPyObjVectorOfObj(PyObject *pyLi, swig_type_info *ty, cons for(int i=0;i ret=fillArrayWithPyListDbl2(value,tmp1,tmp2); + sw=4; + f=ret; + return &f[0]; } - return &f[0]; + catch(INTERP_KERNEL::Exception& e) { throw e; } } void *argp; int status=SWIG_ConvertPtr(value,&argp,SWIGTYPE_p_ParaMEDMEM__DataArrayDouble,0|0); @@ -1409,3 +1594,83 @@ static const double *convertObjToPossibleCpp5_Safe2(PyObject *value, int& sw, do } throw INTERP_KERNEL::Exception("4 types accepted : integer, double, DataArrayDouble, DataArrayDoubleTuple"); } + +/*! + * if python int -> cpp int sw=1 + * if python list[int] -> cpp vector sw=2 + * if python tuple[int] -> cpp vector sw=2 + * if python DataArrayInt -> cpp DataArrayInt sw=3 + * if python DataArrayIntTuple -> cpp DataArrayIntTuple sw=4 + * + * switch between (int,vector,DataArrayInt) + */ +static const int *convertObjToPossibleCpp1_Safe(PyObject *value, int& sw, int& sz, int& iTyypp, std::vector& stdvecTyypp) throw(INTERP_KERNEL::Exception) +{ + sw=-1; + if(PyInt_Check(value)) + { + iTyypp=(int)PyInt_AS_LONG(value); + sw=1; sz=1; + return &iTyypp; + } + if(PyTuple_Check(value)) + { + int size=PyTuple_Size(value); + stdvecTyypp.resize(size); + for(int i=0;i(argp); + if(daIntTyypp) + { + sw=3; sz=daIntTyypp->getNbOfElems(); + return daIntTyypp->begin(); + } + else + { + sz=0; + return 0; + } + } + status=SWIG_ConvertPtr(value,&argp,SWIGTYPE_p_ParaMEDMEM__DataArrayIntTuple,0|0); + if(SWIG_IsOK(status)) + { + ParaMEDMEM::DataArrayIntTuple *daIntTuple=reinterpret_cast< ParaMEDMEM::DataArrayIntTuple * >(argp); + sw=4; sz=daIntTuple->getNumberOfCompo(); + return daIntTuple->getConstPointer(); + } + throw INTERP_KERNEL::Exception("5 types accepted : integer, tuple of integer, list of integer, DataArrayInt, DataArrayIntTuple"); +} diff --git a/src/MEDLoader/MEDFileData.cxx b/src/MEDLoader/MEDFileData.cxx index b18c3cb42..61f1429f3 100644 --- a/src/MEDLoader/MEDFileData.cxx +++ b/src/MEDLoader/MEDFileData.cxx @@ -129,7 +129,6 @@ bool MEDFileData::unPolyzeMeshes() throw(INTERP_KERNEL::Exception) MEDFileMeshes *ms=_meshes; if(!ms) return false; - bool ret=false; std::vector< MEDFileMesh * > meshesImpacted; std::vector< DataArrayInt * > renumParamsOfMeshImpacted;//same size as meshesImpacted std::vector< std::vector > oldCodeOfMeshImpacted,newCodeOfMeshImpacted;//same size as meshesImpacted diff --git a/src/MEDLoader/MEDFileField.cxx b/src/MEDLoader/MEDFileField.cxx index cf851c2e9..70d126a7d 100644 --- a/src/MEDLoader/MEDFileField.cxx +++ b/src/MEDLoader/MEDFileField.cxx @@ -254,18 +254,32 @@ void MEDFileFieldPerMeshPerTypePerDisc::assignFieldNoProfile(int& start, int off } /*! - * Leaf method of field with profile assignement. - * @param pflName input containing name of profile if any. 0 if no profile. - * @param multiTypePfl input containing the profile array \b including \b all \b types. This array is usefull only for GAUSS_NE. - * @param idsInPfl input containing the ids in the profile 'multiTypePfl' concerning the current geo type. + * Leaf method of field with profile assignement. This method is the most general one. No optimization is done here. + * \param [in] pflName input containing name of profile if any. 0 if no profile (except for GAUSS_PT where a no profile can hide a profile when splitted by loc_id). + * \param [in] multiTypePfl is the end user profile specified in high level API + * \param [in] idsInPfl is the selection into the \a multiTypePfl whole profile that corresponds to the current geometric type. + * \param [in] locIds is the profile needed to be created for MED file format. It can be null if all cells of current geometric type are fetched in \a multiTypePfl. + * \b WARNING if not null the MED file profile can be subdivided again in case of Gauss points. + * \param [in] mesh is the mesh coming from the MEDFileMesh instance in correspondance with the MEDFileField. The mesh inside the \a field is simply ignored. */ -void MEDFileFieldPerMeshPerTypePerDisc::assignFieldProfile(int& start, const char *pflName, const DataArrayInt *multiTypePfl, const DataArrayInt *idsInPfl, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception) +void MEDFileFieldPerMeshPerTypePerDisc::assignFieldProfile(int& start, const DataArrayInt *multiTypePfl, const DataArrayInt *idsInPfl, DataArrayInt *locIds, int nbOfEltsInWholeMesh, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception) { - if(pflName) - _profile=pflName; - else - _profile.clear(); + _profile.clear(); _type=field->getTypeOfField(); + std::string pflName(multiTypePfl->getName()); + std::ostringstream oss; oss << pflName; + if(_type!=ON_NODES) { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(getGeoType()); oss << "_" << cm.getRepr(); } else { oss << "_NODE"; } + if(locIds) + { + if(pflName.empty()) + throw INTERP_KERNEL::Exception("MEDFileFieldPerMeshPerTypePerDisc::assignFieldProfile : existing profile with empty name !"); + if(_type!=ON_GAUSS_PT) + { + locIds->setName(oss.str().c_str()); + glob.appendProfile(locIds); + _profile=oss.str(); + } + } const DataArrayDouble *da=field->getArray(); _start=start; switch(_type) @@ -288,7 +302,7 @@ void MEDFileFieldPerMeshPerTypePerDisc::assignFieldProfile(int& start, const cha { MEDCouplingAutoRefCountObjectPtr arr=field->getDiscretization()->getOffsetArr(mesh); MEDCouplingAutoRefCountObjectPtr arr2=arr->deltaShiftIndex(); - MEDCouplingAutoRefCountObjectPtr arr3=arr2->selectByTupleId(multiTypePfl->getConstPointer(),multiTypePfl->getConstPointer()+multiTypePfl->getNumberOfTuples()); + MEDCouplingAutoRefCountObjectPtr arr3=arr2->selectByTupleId(multiTypePfl->begin(),multiTypePfl->end()); arr3->computeOffsets2(); MEDCouplingAutoRefCountObjectPtr tmp=idsInPfl->buildExplicitArrByRanges(arr3); int trueNval=tmp->getNumberOfTuples(); @@ -299,7 +313,52 @@ void MEDFileFieldPerMeshPerTypePerDisc::assignFieldProfile(int& start, const cha } case ON_GAUSS_PT: { - throw INTERP_KERNEL::Exception("MEDFileFieldPerMeshPerTypePerDisc::assignFieldProfile : not implemented yet for profiles on gauss points !"); + const MEDCouplingFieldDiscretizationGauss *disc2=dynamic_cast(field->getDiscretization()); + if(!disc2) + throw INTERP_KERNEL::Exception("addNewEntryIfNecessaryGauss : invalid call to this method ! Internal Error !"); + const DataArrayInt *da1=disc2->getArrayOfDiscIds(); + const MEDCouplingGaussLocalization& gsLoc=field->getGaussLocalization(_loc_id); + MEDCouplingAutoRefCountObjectPtr da2=da1->selectByTupleId(idsInPfl->begin(),idsInPfl->end()); + MEDCouplingAutoRefCountObjectPtr da3=da2->getIdsEqual(_loc_id); + MEDCouplingAutoRefCountObjectPtr da4=idsInPfl->selectByTupleId(da3->begin(),da3->end()); + // + MEDCouplingAutoRefCountObjectPtr mesh2=mesh->buildPart(multiTypePfl->begin(),multiTypePfl->end()); + MEDCouplingAutoRefCountObjectPtr arr=disc2->getOffsetArr(mesh2); + // + MEDCouplingAutoRefCountObjectPtr tmp=DataArrayInt::New(); + int trueNval=0; + for(const int *pt=da4->begin();pt!=da4->end();pt++) + trueNval+=arr->getIJ(*pt+1,0)-arr->getIJ(*pt,0); + tmp->alloc(trueNval,1); + int *tmpPtr=tmp->getPointer(); + for(const int *pt=da4->begin();pt!=da4->end();pt++) + for(int j=arr->getIJ(*pt,0);jgetIJ(*pt+1,0);j++) + *tmpPtr++=j; + // + _nval=da4->getNumberOfTuples(); + getArray()->setContigPartOfSelectedValues(_start,da,tmp); + _end=_start+trueNval; + oss << "_loc_" << _loc_id; + if(locIds) + { + MEDCouplingAutoRefCountObjectPtr da5=locIds->selectByTupleId(da3->begin(),da3->end()); + da5->setName(oss.str().c_str()); + glob.appendProfile(da5); + _profile=oss.str(); + } + else + { + if(da3->getNumberOfTuples()!=nbOfEltsInWholeMesh || !da3->isIdentity()) + { + da3->setName(oss.str().c_str()); + glob.appendProfile(da3); + _profile=oss.str(); + } + } + std::ostringstream oss2; oss2 << "Loc_" << getName() << "_" << INTERP_KERNEL::CellModel::GetCellModel(getGeoType()).getRepr() << "_" << _loc_id; + _localization=oss2.str(); + glob.appendLoc(_localization.c_str(),getGeoType(),gsLoc.getRefCoords(),gsLoc.getGaussCoords(),gsLoc.getWeights()); + break; } default: throw INTERP_KERNEL::Exception("MEDFileFieldPerMeshPerTypePerDisc::assignFieldProfile : not implemented yet for such discretization type of field !"); @@ -620,10 +679,10 @@ int MEDFileFieldPerMeshPerTypePerDisc::fillEltIdsFromCode(int offset, const std: _loc_id=offset; std::ostringstream oss; std::size_t nbOfType=codeOfMesh.size()/3; - std::size_t found=-1; + int found=-1; for(std::size_t i=0;igetNumberOfTuples() << " whereas the number of ids is set to " << _nval << " for this geometric type !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); } - int offset=codeOfMesh[3*found+2]; + int offset2=codeOfMesh[3*found+2]; for(const int *pflId=pfl->begin();pflId!=pfl->end();pflId++) { if(*pflId_loc_id)==geoType && (*it)->_nval==nbMeshEntities) { if(!isPfl) - if((*it)->_profile.empty()) - break; - else - if(!(*it)->_profile.empty()) - { - const DataArrayInt *pfl=glob.getProfile((*it)->_profile.c_str()); - if(pfl->isEqualWithoutConsideringStr(*idsOfMeshElt)) - break; - } + { + if((*it)->_profile.empty()) + break; + else + if(!(*it)->_profile.empty()) + { + const DataArrayInt *pfl=glob.getProfile((*it)->_profile.c_str()); + if(pfl->isEqualWithoutConsideringStr(*idsOfMeshElt)) + break; + } + } } } if(it==entriesOnSameDisc.end()) @@ -865,28 +926,20 @@ void MEDFileFieldPerMeshPerType::assignFieldNoProfile(int& start, int offset, in _field_pm_pt_pd[*it]->assignFieldNoProfile(start,offset,nbOfCells,field,glob); } -void MEDFileFieldPerMeshPerType::assignFieldProfile(int& start, const DataArrayInt *multiTypePfl, const DataArrayInt *idsInPfl, DataArrayInt *locIds, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception) +/*! + * This method is the most general one. No optimization is done here. + * \param [in] multiTypePfl is the end user profile specified in high level API + * \param [in] idsInPfl is the selection into the \a multiTypePfl whole profile that corresponds to the current geometric type. + * \param [in] locIds is the profile needed to be created for MED file format. It can be null if all cells of current geometric type are fetched in \a multiTypePfl. + * \b WARNING if not null the MED file profile can be subdivided again in case of Gauss points. + * \param [in] nbOfEltsInWholeMesh nb of elts of type \a this->_geo_type in \b WHOLE mesh + * \param [in] mesh is the mesh coming from the MEDFileMesh instance in correspondance with the MEDFileField. The mesh inside the \a field is simply ignored. + */ +void MEDFileFieldPerMeshPerType::assignFieldProfile(int& start, const DataArrayInt *multiTypePfl, const DataArrayInt *idsInPfl, DataArrayInt *locIds, int nbOfEltsInWholeMesh, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception) { std::vector pos=addNewEntryIfNecessary(field,idsInPfl); - if(locIds) - { - // - std::string pflName(locIds->getName()); - if(pflName.empty()) - throw INTERP_KERNEL::Exception("MEDFileFieldPerMeshPerType::assignFieldProfile : existing profile with empty name !"); - const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(_geo_type); - std::ostringstream oss; oss << pflName << "_" << cm.getRepr(); - locIds->setName(oss.str().c_str()); - glob.appendProfile(locIds); - // - for(std::vector::const_iterator it=pos.begin();it!=pos.end();it++) - _field_pm_pt_pd[*it]->assignFieldProfile(start,oss.str().c_str(),multiTypePfl,idsInPfl,field,mesh,glob); - } - else - { - for(std::vector::const_iterator it=pos.begin();it!=pos.end();it++) - _field_pm_pt_pd[*it]->assignFieldProfile(start,0,multiTypePfl,idsInPfl,field,mesh,glob); - } + for(std::vector::const_iterator it=pos.begin();it!=pos.end();it++) + _field_pm_pt_pd[*it]->assignFieldProfile(start,multiTypePfl,idsInPfl,locIds,nbOfEltsInWholeMesh,field,mesh,glob); } void MEDFileFieldPerMeshPerType::assignNodeFieldNoProfile(int& start, const MEDCouplingFieldDouble *field, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception) @@ -898,17 +951,11 @@ void MEDFileFieldPerMeshPerType::assignNodeFieldNoProfile(int& start, const MEDC void MEDFileFieldPerMeshPerType::assignNodeFieldProfile(int& start, const DataArrayInt *pfl, const MEDCouplingFieldDouble *field, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception) { - std::string pflName(pfl->getName()); - if(pflName.empty()) - throw INTERP_KERNEL::Exception("MEDFileFieldPerMeshPerType::assignNodeFieldProfile : existing profile with empty name !"); - std::ostringstream oss; oss << pflName << "_NODE"; MEDCouplingAutoRefCountObjectPtr pfl2=pfl->deepCpy(); - pfl2->setName(oss.str().c_str()); - glob.appendProfile(pfl2); // _field_pm_pt_pd.resize(1); _field_pm_pt_pd[0]=MEDFileFieldPerMeshPerTypePerDisc::New(this,ON_NODES,-3); - _field_pm_pt_pd[0]->assignFieldProfile(start,oss.str().c_str(),pfl,pfl2,field,0,glob);//mesh is not requested so 0 is send. + _field_pm_pt_pd[0]->assignFieldProfile(start,pfl,pfl2,pfl2,-1,field,0,glob);//mesh is not requested so 0 is send. } std::vector MEDFileFieldPerMeshPerType::addNewEntryIfNecessary(const MEDCouplingFieldDouble *field, int offset, int nbOfCells) throw(INTERP_KERNEL::Exception) @@ -1043,7 +1090,7 @@ std::vector MEDFileFieldPerMeshPerType::addNewEntryIfNecessaryGauss(const M if(!disc2) throw INTERP_KERNEL::Exception("addNewEntryIfNecessaryGauss : invalid call to this method ! Internal Error !"); const DataArrayInt *da=disc2->getArrayOfDiscIds(); - MEDCouplingAutoRefCountObjectPtr da2=da->selectByTupleId(subCells->getConstPointer(),subCells->getConstPointer()+subCells->getNumberOfTuples()); + MEDCouplingAutoRefCountObjectPtr da2=da->selectByTupleIdSafe(subCells->getConstPointer(),subCells->getConstPointer()+subCells->getNumberOfTuples()); std::set retTmp=da2->getDifferentValues(); if(retTmp.find(-1)!=retTmp.end()) throw INTERP_KERNEL::Exception("addNewEntryIfNecessaryGauss : some cells have no dicretization description !"); @@ -1403,24 +1450,6 @@ void MEDFileFieldPerMesh::copyTinyInfoFrom(const MEDCouplingMesh *mesh) throw(IN mesh->getTime(_mesh_iteration,_mesh_order); } -void MEDFileFieldPerMesh::assignFieldProfile(int& start, const DataArrayInt *multiTypePfl, const std::vector& code, const std::vector& idsInPflPerType, const std::vector& idsPerType, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception) -{ - int nbOfTypes=code.size()/3; - bool isProfile=false; - for(int i=0;i& code, const MEDCouplingFieldDouble *field, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception) { int nbOfTypes=code.size()/3; @@ -1437,8 +1466,14 @@ void MEDFileFieldPerMesh::assignFieldNoProfileNoRenum(int& start, const std::vec /*! * This method is the most general one. No optimization is done here. + * \param [in] multiTypePfl is the end user profile specified in high level API + * \param [in] code is the code of \a mesh[multiTypePfl] mesh. It is of size of number of different geometric types into \a mesh[multiTypePfl]. + * \param [in] code2 is the code of the \b WHOLE mesh on the same level. So all types in \a code are in \a code2. + * \param [in] idsInPflPerType is the selection into the \a multiTypePfl whole profile that corresponds to the given geometric type. This vector is always 3 times smaller than \a code. + * \param [in] idsPerType is a vector containing the profiles needed to be created for MED file format. \b WARNING these processed MED file profiles can be subdivided again in case of Gauss points. + * \param [in] mesh is the mesh coming from the MEDFileMesh instance in correspondance with the MEDFileField. The mesh inside the \a field is simply ignored. */ -void MEDFileFieldPerMesh::assignFieldProfileGeneral(int& start, const DataArrayInt *multiTypePfl, const std::vector& code, const std::vector& idsInPflPerType, const std::vector& idsPerType, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception) +void MEDFileFieldPerMesh::assignFieldProfile(int& start, const DataArrayInt *multiTypePfl, const std::vector& code, const std::vector& code2, const std::vector& idsInPflPerType, const std::vector& idsPerType, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception) { int nbOfTypes=code.size()/3; for(int i=0;iassignFieldProfile(start,multiTypePfl,idsInPflPerType[i],pfl,field,mesh,glob); + int nbOfTupes2=code2.size()/3; + int found=0; + for(;foundassignFieldProfile(start,multiTypePfl,idsInPflPerType[i],pfl,code2[3*found+1],field,mesh,glob); } } @@ -1831,6 +1873,9 @@ void MEDFileFieldPerMesh::changeLocsRefsNamesGen(const std::vector< std::pairchangeLocsRefsNamesGen(mapOfModif); } +/*! + * \param [in] mesh is the whole mesh + */ MEDCouplingFieldDouble *MEDFileFieldPerMesh::getFieldOnMeshAtLevel(TypeOfField type, const MEDFileFieldGlobsReal *glob, const MEDCouplingMesh *mesh, bool& isPfl) const throw(INTERP_KERNEL::Exception) { if(_field_pm_pt.empty()) @@ -2006,7 +2051,8 @@ int MEDFileFieldPerMesh::addNewEntryIfNecessary(INTERP_KERNEL::NormalizedCellTyp } /*! - * 'dads' and 'locs' input parameters have the same number of elements. + * 'dads' and 'locs' input parameters have the same number of elements + * \param [in] mesh is \b NOT the global mesh, but the possibly reduced mesh. \a mesh parameter will be directly aggregated in the returned field */ MEDCouplingFieldDouble *MEDFileFieldPerMesh::finishField(TypeOfField type, const MEDFileFieldGlobsReal *glob, const std::vector< std::pair >& dads, const std::vector& locs, @@ -2047,6 +2093,7 @@ MEDCouplingFieldDouble *MEDFileFieldPerMesh::finishField(TypeOfField type, const * 'dads', 'locs' and 'geoTypes' input parameters have the same number of elements. * No check of this is performed. 'da' array contains an array in old2New style to be applyied to mesh to obtain the right support. * The order of cells in the returned field is those imposed by the profile. + * \param [in] mesh is the global mesh. */ MEDCouplingFieldDouble *MEDFileFieldPerMesh::finishField2(TypeOfField type, const MEDFileFieldGlobsReal *glob, const std::vector >& dads, const std::vector& locs, @@ -2059,11 +2106,10 @@ MEDCouplingFieldDouble *MEDFileFieldPerMesh::finishField2(TypeOfField type, cons if(nbOfTuples==mesh->getNumberOfCells()) return finishField(type,glob,dads,locs,mesh,isPfl); } - MEDCouplingAutoRefCountObjectPtr ret=finishField(type,glob,dads,locs,mesh,isPfl); - isPfl=true; MEDCouplingAutoRefCountObjectPtr m2=mesh->buildPart(da->getConstPointer(),da->getConstPointer()+da->getNbOfElems()); m2->setName(mesh->getName()); - ret->setMesh(m2); + MEDCouplingAutoRefCountObjectPtr ret=finishField(type,glob,dads,locs,m2,isPfl); + isPfl=true; ret->incrRef(); return ret; } @@ -3420,18 +3466,14 @@ void MEDFileField1TSWithoutSDA::setFieldNoProfileSBT(const MEDCouplingFieldDoubl TypeOfField type=field->getTypeOfField(); std::vector dummy; int start=copyTinyInfoFrom(field); + int pos=addNewEntryIfNecessary(mesh); if(type!=ON_NODES) { std::vector code=MEDFileField1TSWithoutSDA::CheckSBTMesh(mesh); - // - int pos=addNewEntryIfNecessary(mesh); - _field_per_mesh[pos]->assignFieldProfile(start,0,code,dummy,dummy,field,0,glob);//mesh is set to 0 because no external mesh is needed to be sent because no profile. + _field_per_mesh[pos]->assignFieldNoProfileNoRenum(start,code,field,glob); } else - { - int pos=addNewEntryIfNecessary(mesh); - _field_per_mesh[pos]->assignNodeFieldNoProfile(start,field,glob); - } + _field_per_mesh[pos]->assignNodeFieldNoProfile(start,field,glob); } /*! @@ -3443,11 +3485,12 @@ void MEDFileField1TSWithoutSDA::setFieldProfile(const MEDCouplingFieldDouble *fi int start=copyTinyInfoFrom(field); std::vector idsInPflPerType; std::vector idsPerType; - std::vector code; + std::vector code,code2; MEDCouplingAutoRefCountObjectPtr m=mesh->getGenMeshAtLevel(meshDimRelToMax); if(type!=ON_NODES) { m->splitProfilePerType(profile,code,idsInPflPerType,idsPerType); + code2=m->getDistributionOfTypes(); // std::vector< MEDCouplingAutoRefCountObjectPtr > idsInPflPerType2(idsInPflPerType.size()); for(std::size_t i=0;iassignFieldProfile(start,profile,code,idsInPflPerType,idsPerType,field,m,glob); + _field_per_mesh[pos]->assignFieldProfile(start,profile,code,code2,idsInPflPerType,idsPerType,field,m,glob); } else { @@ -3498,6 +3541,9 @@ MEDCouplingFieldDouble *MEDFileField1TSWithoutSDA::getFieldAtTopLevel(TypeOfFiel return MEDFileField1TSWithoutSDA::getFieldOnMeshAtLevel(type,meshDimRelToMax,renumPol,glob,mm); } +/*! + * \param [in] mesh is the whole mesh. + */ MEDCouplingFieldDouble *MEDFileField1TSWithoutSDA::getFieldOnMeshAtLevel(TypeOfField type, int renumPol, const MEDFileFieldGlobsReal *glob, const MEDCouplingMesh *mesh, const DataArrayInt *cellRenum, const DataArrayInt *nodeRenum) const throw(INTERP_KERNEL::Exception) { static const char msg1[]="MEDFileField1TSWithoutSDA::getFieldOnMeshAtLevel : request for a renumbered field following mesh numbering whereas it is a profile field !"; @@ -3597,7 +3643,7 @@ DataArrayDouble *MEDFileField1TSWithoutSDA::getUndergroundDataArrayExt(std::vect } MEDFileField1TSWithoutSDA::MEDFileField1TSWithoutSDA(const char *fieldName, int csit, int fieldtype, int iteration, int order, - const std::vector& infos):_csit(csit),_field_type(fieldtype),_iteration(iteration),_order(order) + const std::vector& infos):_iteration(iteration),_order(order),_csit(csit),_field_type(fieldtype) { DataArrayDouble *arr=getOrCreateAndGetArray(); arr->setName(fieldName); @@ -3747,7 +3793,7 @@ void MEDFileField1TS::write(const char *fileName, int mode) const throw(INTERP_K } MEDFileField1TS::MEDFileField1TS(const char *fileName, const char *fieldName, int iteration, int order) throw(INTERP_KERNEL::Exception) -try:_content(MEDFileField1TSWithoutSDA::New(fieldName,-1,-1,iteration,order,std::vector())),MEDFileFieldGlobsReal(fileName) +try:MEDFileFieldGlobsReal(fileName),_content(MEDFileField1TSWithoutSDA::New(fieldName,-1,-1,iteration,order,std::vector())) { MEDFileUtilities::CheckFileForRead(fileName); MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,MED_ACC_RDONLY); @@ -4218,9 +4264,8 @@ MEDFileFieldMultiTSWithoutSDA::MEDFileFieldMultiTSWithoutSDA(med_idt fid, int fi try:_name("") { med_field_type typcha; - int nbstep2=-1; // - int ncomp=MEDfieldnComponent(fid,1); + int ncomp=MEDfieldnComponent(fid,fieldId+1); INTERP_KERNEL::AutoPtr comp=MEDLoaderBase::buildEmptyString(ncomp*MED_SNAME_SIZE); INTERP_KERNEL::AutoPtr unit=MEDLoaderBase::buildEmptyString(ncomp*MED_SNAME_SIZE); INTERP_KERNEL::AutoPtr dtunit=MEDLoaderBase::buildEmptyString(MED_LNAME_SIZE); @@ -4539,12 +4584,12 @@ int MEDFileFieldMultiTSWithoutSDA::getPosOfTimeStep(int iteration, int order) co const MEDFileField1TSWithoutSDA *tmp(*it); if(tmp) { - int it,ord; - tmp->getTime(it,ord); - if(it==iteration && order==ord) + int it2,ord; + tmp->getTime(it2,ord); + if(it2==iteration && order==ord) return ret; else - oss << "(" << it << "," << ord << "), "; + oss << "(" << it2 << "," << ord << "), "; } } throw INTERP_KERNEL::Exception(oss.str().c_str()); @@ -4560,8 +4605,8 @@ int MEDFileFieldMultiTSWithoutSDA::getPosGivenTime(double time, double eps) cons const MEDFileField1TSWithoutSDA *tmp(*it); if(tmp) { - int it,ord; - double ti=tmp->getTime(it,ord); + int it2,ord; + double ti=tmp->getTime(it2,ord); if(fabs(time-ti)& dad, std::string& pfl, std::string& loc) const throw(INTERP_KERNEL::Exception); void writeLL(med_idt fid) const throw(INTERP_KERNEL::Exception); @@ -165,7 +165,7 @@ namespace ParaMEDMEM static MEDFileFieldPerMeshPerType *New(MEDFileFieldPerMesh *fath, INTERP_KERNEL::NormalizedCellType geoType) throw(INTERP_KERNEL::Exception); static MEDFileFieldPerMeshPerType *NewOnRead(med_idt fid, MEDFileFieldPerMesh *fath, TypeOfField type, INTERP_KERNEL::NormalizedCellType geoType) throw(INTERP_KERNEL::Exception); void assignFieldNoProfile(int& start, int offset, int nbOfCells, const MEDCouplingFieldDouble *field, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception); - void assignFieldProfile(int& start, const DataArrayInt *multiTypePfl, const DataArrayInt *idsInPfl, DataArrayInt *locIds, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception); + void assignFieldProfile(int& start, const DataArrayInt *multiTypePfl, const DataArrayInt *idsInPfl, DataArrayInt *locIds, int nbOfEltsInWholeMesh, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception); void assignNodeFieldNoProfile(int& start, const MEDCouplingFieldDouble *field, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception); void assignNodeFieldProfile(int& start, const DataArrayInt *pfl, const MEDCouplingFieldDouble *field, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception); const MEDFileFieldPerMesh *getFather() const; @@ -219,8 +219,7 @@ namespace ParaMEDMEM static MEDFileFieldPerMesh *NewOnRead(med_idt fid, MEDFileField1TSWithoutSDA *fath, int meshCsit, int meshIteration, int meshOrder) throw(INTERP_KERNEL::Exception); void simpleRepr(int bkOffset,std::ostream& oss, int id) const; void copyTinyInfoFrom(const MEDCouplingMesh *mesh) throw(INTERP_KERNEL::Exception); - void assignFieldProfile(int& start, const DataArrayInt *multiTypePfl, const std::vector& code, const std::vector& idsInPflPerType, const std::vector& idsPerType, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception); - void assignFieldProfileGeneral(int& start, const DataArrayInt *multiTypePfl, const std::vector& code, const std::vector& idsInPflPerType, const std::vector& idsPerType, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception); + void assignFieldProfile(int& start, const DataArrayInt *multiTypePfl, const std::vector& code, const std::vector& code2, const std::vector& idsInPflPerType, const std::vector& idsPerType, const MEDCouplingFieldDouble *field, const MEDCouplingMesh *mesh, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception); void assignFieldNoProfileNoRenum(int& start, const std::vector& code, const MEDCouplingFieldDouble *field, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception); void assignNodeFieldNoProfile(int& start, const MEDCouplingFieldDouble *field, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception); void assignNodeFieldProfile(int& start, const DataArrayInt *pfl, const MEDCouplingFieldDouble *field, MEDFileFieldGlobsReal& glob) throw(INTERP_KERNEL::Exception); diff --git a/src/MEDLoader/MEDFileMesh.cxx b/src/MEDLoader/MEDFileMesh.cxx index 6f77ac217..5c5ccd8f8 100644 --- a/src/MEDLoader/MEDFileMesh.cxx +++ b/src/MEDLoader/MEDFileMesh.cxx @@ -217,8 +217,8 @@ std::vector MEDFileMesh::getFamiliesOnGroups(const std::vector grps=getGroupsNames(); oss << "\" !\nAvailable groups are :"; - std::copy(grps.begin(),grps.end(),std::ostream_iterator(oss," ")); + std::vector grps2=getGroupsNames(); oss << "\" !\nAvailable groups are :"; + std::copy(grps2.begin(),grps2.end(),std::ostream_iterator(oss," ")); throw INTERP_KERNEL::Exception(oss.str().c_str()); } fams.insert((*it2).second.begin(),(*it2).second.end()); @@ -2132,7 +2132,7 @@ bool MEDFileUMesh::unPolyze(std::vector& oldCode, std::vector& newCode std::vector< MEDCouplingAutoRefCountObjectPtr > memorySaverIfThrow;//same than renumCellsSplited only in case of throw int start=0; int end=0; - for(std::vector::const_reverse_iterator it=levs.rbegin();it!=levs.rend();it++) + for(std::vector::reverse_iterator it=levs.rbegin();it!=levs.rend();it++) { MEDCouplingAutoRefCountObjectPtr m=getMeshAtLevel(*it); std::vector code1=m->getDistributionOfTypes(); diff --git a/src/MEDLoader/MEDFileMeshLL.cxx b/src/MEDLoader/MEDFileMeshLL.cxx index 2c3c77d9b..cfb86ad46 100644 --- a/src/MEDLoader/MEDFileMeshLL.cxx +++ b/src/MEDLoader/MEDFileMeshLL.cxx @@ -652,7 +652,6 @@ void MEDFileUMeshSplitL1::eraseFamilyField() void MEDFileUMeshSplitL1::setGroupsFromScratch(const std::vector& ms, std::map& familyIds, std::map >& groups) throw(INTERP_KERNEL::Exception) { - int sz=ms.size(); std::vector< DataArrayInt * > corr; _m=MEDCouplingUMesh::FuseUMeshesOnSameCoords(ms,0,corr); std::vector< MEDCouplingAutoRefCountObjectPtr > corrMSafe(corr.begin(),corr.end()); diff --git a/src/MEDLoader/MEDLoader.cxx b/src/MEDLoader/MEDLoader.cxx index 60e8773ec..8fd883859 100644 --- a/src/MEDLoader/MEDLoader.cxx +++ b/src/MEDLoader/MEDLoader.cxx @@ -261,11 +261,11 @@ void MEDLoader::MEDConnOfOneElemType::releaseArray() delete [] _global; } -MEDLoader::MEDFieldDoublePerCellType::MEDFieldDoublePerCellType(INTERP_KERNEL::NormalizedCellType type, double *values, int ncomp, int ntuple, - const int *cellIdPerType, const char *locName):_ntuple(ntuple),_ncomp(ncomp),_values(values),_type(type) +MEDLoader::MEDFieldDoublePerCellType::MEDFieldDoublePerCellType(INTERP_KERNEL::NormalizedCellType type, double *values, int ncomp, int nGeoElt, int nbi, + const int *cellIdPerType, const char *locName):_ngeo_elt(nGeoElt),_nbi(nbi),_ncomp(ncomp),_values(values),_type(type) { if(cellIdPerType) - _cell_id_per_type.insert(_cell_id_per_type.end(),cellIdPerType,cellIdPerType+ntuple); + _cell_id_per_type.insert(_cell_id_per_type.end(),cellIdPerType,cellIdPerType+nGeoElt); if(locName) _loc_name=locName; } @@ -308,6 +308,7 @@ void MEDLoaderNS::fillGaussDataOnField(const char *fileName, const std::list::const_iterator iter=data.begin();iter!=data.end();iter++) { const std::string& loc=(*iter).getLocName(); @@ -329,7 +330,16 @@ void MEDLoaderNS::fillGaussDataOnField(const char *fileName, const std::list refcoo(nbPtPerCell*dim),gscoo(nbOfGaussPt*dim),w(nbOfGaussPt); MEDlocalizationRd(fid,(*iter).getLocName().c_str(),MED_FULL_INTERLACE,&refcoo[0],&gscoo[0],&w[0]); - f->setGaussLocalizationOnType((*iter).getType(),refcoo,gscoo,w); + if((*iter).getCellIdPerType().empty()) + f->setGaussLocalizationOnType((*iter).getType(),refcoo,gscoo,w); + else + { + MEDCouplingAutoRefCountObjectPtr pfl=DataArrayInt::New(); + pfl->alloc((*iter).getCellIdPerType().size(),1); + pfl->iota(offset); + f->setGaussLocalizationOnCells(pfl->begin(),pfl->end(),refcoo,gscoo,w); + } + offset+=(*iter).getNbOfGeoElt(); } MEDfileClose(fid); } @@ -1106,27 +1116,33 @@ void MEDLoaderNS::readFieldDoubleDataInMedFile(const char *fileName, const char { if(nbPdt>0) { - int profilesize,nbi; - int nval=MEDfieldnValueWithProfile(fid,fieldName,numdt,numo,tabEnt[typeOfOutField],tabType[typeOfOutField][j],1,MED_COMPACT_PFLMODE,pflname,&profilesize,locname,&nbi); - if(nval>0) + INTERP_KERNEL::AutoPtr pflDummy=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE); + INTERP_KERNEL::AutoPtr locDummy=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE); + int nbProfiles=MEDfieldnProfile(fid,fieldName,numdt,numo,tabEnt[typeOfOutField],tabType[typeOfOutField][j],pflDummy,locDummy); + for(int kk=0;kk0) { - delete [] valr; - continue; + double *valr=new double[ncomp*nval*nbi]; + MEDfieldValueWithProfileRd(fid,fieldName,iteration,order,tabEnt[typeOfOutField],tabType[typeOfOutField][j],MED_COMPACT_PFLMODE, + pflname,MED_FULL_INTERLACE,MED_ALL_CONSTITUENT,(unsigned char*)valr); + std::string tmp(locname); + if((locname[0]!='\0' && (typeOfOutField!=ON_GAUSS_PT)) + || (locname[0]=='\0' && typeOfOutField==ON_GAUSS_PT)) + { + delete [] valr; + continue; + } + INTERP_KERNEL::AutoPtr pfl=0; + if(pflname[0]!='\0') + { + pfl=new int[nval]; + MEDprofileRd(fid,pflname,pfl); + } + field.push_back(MEDLoader::MEDFieldDoublePerCellType(typmai2[j],valr,ncomp,nval,nbi,pfl,locname)); } - INTERP_KERNEL::AutoPtr pfl=0; - if(pflname[0]!='\0') - { - pfl=new int[nval]; - MEDprofileRd(fid,pflname,pfl); - } - field.push_back(MEDLoader::MEDFieldDoublePerCellType(typmai2[j],valr,ncomp,nval*nbi,pfl,locname)); } } } @@ -1884,32 +1900,26 @@ ParaMEDMEM::MEDCouplingFieldDouble *MEDLoaderNS::readFieldDoubleLev2(const char throw INTERP_KERNEL::Exception(oss.str().c_str()); } //for profiles - ParaMEDMEM::MEDCouplingUMesh *newMesh=0; + MEDCouplingAutoRefCountObjectPtr newMesh; std::string mName(mesh->getName()); - for(std::list::const_iterator iter=fieldPerCellType.begin();iter!=fieldPerCellType.end();iter++) + if(typeOfOutField==ON_NODES) { - const std::vector& cellIds=(*iter).getCellIdPerType(); - if(!cellIds.empty()) + for(std::list::const_iterator iter=fieldPerCellType.begin();iter!=fieldPerCellType.end();iter++) { - std::vector ci(cellIds.size()); - std::transform(cellIds.begin(),cellIds.end(),ci.begin(),std::bind2nd(std::plus(),-1)); - ParaMEDMEM::MEDCouplingUMesh *mesh2=0; - if(typeOfOutField==ON_CELLS) + const std::vector& cellIds=(*iter).getCellIdPerType(); + if(!cellIds.empty()) { - if(newMesh) - mesh2=newMesh->keepSpecifiedCells((*iter).getType(),&ci[0],&ci[0]+ci.size()); - else - mesh2=mesh->keepSpecifiedCells((*iter).getType(),&ci[0],&ci[0]+ci.size()); - } - else if(typeOfOutField==ON_NODES) - { - DataArrayInt *da=0,*da2=0; - if(newMesh) + std::vector ci(cellIds.size()); + std::transform(cellIds.begin(),cellIds.end(),ci.begin(),std::bind2nd(std::plus(),-1)); + MEDCouplingAutoRefCountObjectPtr mesh2; + MEDCouplingAutoRefCountObjectPtr da,da2; + if((const ParaMEDMEM::MEDCouplingUMesh *)newMesh) { if((int)ci.size()!=newMesh->getNumberOfNodes()) { da=newMesh->getCellIdsFullyIncludedInNodeIds(&ci[0],&ci[ci.size()]); - mesh2=dynamic_cast(newMesh->buildPartAndReduceNodes(da->getConstPointer(),da->getConstPointer()+da->getNbOfElems(),da2)); + DataArrayInt *tmpp=0; + mesh2=dynamic_cast(newMesh->buildPartAndReduceNodes(da->begin(),da->end(),tmpp)); da2=tmpp; } } else @@ -1917,7 +1927,8 @@ ParaMEDMEM::MEDCouplingFieldDouble *MEDLoaderNS::readFieldDoubleLev2(const char if((int)ci.size()!=mesh->getNumberOfNodes()) { da=mesh->getCellIdsFullyIncludedInNodeIds(&ci[0],&ci[ci.size()]); - mesh2=dynamic_cast(mesh->buildPartAndReduceNodes(da->getConstPointer(),da->getConstPointer()+da->getNbOfElems(),da2)); + DataArrayInt *tmpp=0; + mesh2=dynamic_cast(mesh->buildPartAndReduceNodes(da->begin(),da->end(),tmpp)); da2=tmpp; // int nnodes=mesh2->getNumberOfNodes(); MEDCouplingAutoRefCountObjectPtr da3=DataArrayInt::New(); @@ -1942,32 +1953,47 @@ ParaMEDMEM::MEDCouplingFieldDouble *MEDLoaderNS::readFieldDoubleLev2(const char mesh2->renumberNodes(da2->getConstPointer(),(int)ci.size()); } } - if(da) - da->decrRef(); - if(da2) - da2->decrRef(); + newMesh=mesh2; + } + } + } + else + { + newMesh=const_cast(static_cast(mesh)); mesh->incrRef(); + std::vector types; + for(std::list::const_iterator iter=fieldPerCellType.begin();iter!=fieldPerCellType.end();iter++) + if(std::find(types.begin(),types.end(),(*iter).getType())==types.end()) + types.push_back((*iter).getType()); + for(std::vector::const_iterator it=types.begin();it!=types.end();it++) + { + std::vector cids; + for(std::list::const_iterator iter=fieldPerCellType.begin();iter!=fieldPerCellType.end();iter++) + { + if((*iter).getType()==*it) + { + const std::vector& cellIds=(*iter).getCellIdPerType(); + if(!cellIds.empty()) + std::transform(cellIds.begin(),cellIds.end(),std::back_insert_iterator< std::vector >(cids),std::bind2nd(std::plus(),-1)); + } } - if(newMesh) - newMesh->decrRef(); - newMesh=mesh2; + if(!cids.empty()) + newMesh=newMesh->keepSpecifiedCells(*it,&cids[0],&cids[0]+cids.size()); } } // ParaMEDMEM::MEDCouplingFieldDouble *ret=ParaMEDMEM::MEDCouplingFieldDouble::New(typeOfOutField,ONE_TIME); ret->setName(fieldName); ret->setTime(time,iteration,order); - if(newMesh) + ParaMEDMEM::DataArrayDouble *arr=buildArrayFromRawData(fieldPerCellType,infos); + ret->setArray(arr); + arr->decrRef(); + if((const ParaMEDMEM::MEDCouplingUMesh *)newMesh) { newMesh->setName(mName.c_str());//retrieving mesh name to avoid renaming due to mesh restriction in case of profile. ret->setMesh(newMesh); - newMesh->decrRef(); } else ret->setMesh(mesh); - ParaMEDMEM::DataArrayDouble *arr=buildArrayFromRawData(fieldPerCellType,infos); - ret->setArray(arr); - arr->decrRef(); - // if(typeOfOutField==ON_GAUSS_PT) fillGaussDataOnField(fileName,fieldPerCellType,ret); if(cellRenum) @@ -2376,10 +2402,9 @@ void MEDLoaderNS::appendCellProfileField(const char *fileName, const ParaMEDMEM: std::ostringstream oss; oss << "Pfl" << f->getName() << "_" << number++; MEDLoaderBase::safeStrCpy(oss.str().c_str(),MED_NAME_SIZE,profileName,MEDLoader::_TOO_LONG_STR); const std::vector& ids=(*iter).getCellIdPerType(); - int *profile=new int [ids.size()]; - std::transform(ids.begin(),ids.end(),profile,std::bind2nd(std::plus(),1)); + INTERP_KERNEL::AutoPtr profile=new int [ids.size()]; + std::transform(ids.begin(),ids.end(),(int *)profile,std::bind2nd(std::plus(),1)); MEDprofileWr(fid,profileName,ids.size(),profile); - delete [] profile; MEDfieldValueWithProfileWr(fid,f->getName(),numdt,numo,dt,MED_CELL,typmai3[(int)(*iter).getType()],MED_COMPACT_PFLMODE,profileName, MED_NO_LOCALIZATION,MED_FULL_INTERLACE,MED_ALL_CONSTITUENT,(*iter).getNbOfTuple(),(const unsigned char*)pt); pt+=(*iter).getNbOfTuple()*nbComp; @@ -2405,10 +2430,9 @@ void MEDLoaderNS::appendNodeElementProfileField(const char *fileName, const Para std::ostringstream oss; oss << "Pfl" << f->getName() << "_" << number++; MEDLoaderBase::safeStrCpy(oss.str().c_str(),MED_NAME_SIZE,profileName,MEDLoader::_TOO_LONG_STR); const std::vector& ids=(*iter).getCellIdPerType(); - int *profile=new int [ids.size()]; - std::transform(ids.begin(),ids.end(),profile,std::bind2nd(std::plus(),1)); + INTERP_KERNEL::AutoPtr profile=new int [ids.size()]; + std::transform(ids.begin(),ids.end(),(int *)profile,std::bind2nd(std::plus(),1)); MEDprofileWr(fid,profileName,ids.size(),profile); - delete [] profile; int nbPtPerCell=(int)INTERP_KERNEL::CellModel::GetCellModel((*iter).getType()).getNumberOfNodes(); int nbOfEntity=f->getMesh()->getNumberOfCellsWithType((*iter).getType()); int nbOfValues=nbPtPerCell*nbOfEntity; @@ -2510,25 +2534,75 @@ void MEDLoaderNS::appendFieldDirectly(const char *fileName, const ParaMEDMEM::ME } case ParaMEDMEM::ON_GAUSS_PT: { + INTERP_KERNEL::AutoPtr profileName=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE); std::list split; prepareCellFieldDoubleForWriting(f,0,split); - int idGp=0; + int idGp=0,offset=0,offset2=0; + const double *pt2=0; + INTERP_KERNEL::NormalizedCellType prevType=INTERP_KERNEL::NORM_ERROR; for(std::list::const_iterator iter=split.begin();iter!=split.end();iter++) { + if((*iter).getType()!=prevType) + { + offset=offset2; + prevType=(*iter).getType(); + } INTERP_KERNEL::AutoPtr nomGauss=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE); std::ostringstream oss; oss << "GP_" << f->getName() << idGp++; MEDLoaderBase::safeStrCpy(oss.str().c_str(),MED_NAME_SIZE,nomGauss,MEDLoader::_TOO_LONG_STR); - int id=f->getGaussLocalizationIdOfOneType((*iter).getType()); + std::ostringstream ossPfl; + int id=-1,nbOfEntity=-1; + MEDCouplingAutoRefCountObjectPtr arrTmp; + if((*iter).getCellIdPerType().empty()) + { + id=f->getGaussLocalizationIdOfOneType((*iter).getType()); + nbOfEntity=f->getMesh()->getNumberOfCellsWithType((*iter).getType()); + } + else + { + id=f->getGaussLocalizationIdOfOneCell((*iter).getCellIdPerType()[0]+offset); + nbOfEntity=(int)(*iter).getCellIdPerType().size(); + ossPfl << "Pfl" << f->getName() << "_" << id; + MEDLoaderBase::safeStrCpy(ossPfl.str().c_str(),MED_NAME_SIZE,profileName,MEDLoader::_TOO_LONG_STR); + INTERP_KERNEL::AutoPtr profile=new int[(*iter).getCellIdPerType().size()]; + std::transform((*iter).getCellIdPerType().begin(),(*iter).getCellIdPerType().end(),(int *)profile,std::bind2nd(std::plus(),1)); + MEDprofileWr(fid,profileName,(*iter).getCellIdPerType().size(),profile); + // + MEDCouplingAutoRefCountObjectPtr da3=DataArrayInt::New(); + da3->useArray(const_cast(&((*iter).getCellIdPerType()[0])),false,CPP_DEALLOC,(int)(*iter).getCellIdPerType().size(),1); + MEDCouplingAutoRefCountObjectPtr da4=da3->deepCpy(); + da4->applyLin(1,offset); + // + const MEDCouplingFieldDiscretizationGauss *disc2=static_cast(f->getDiscretization()); + MEDCouplingAutoRefCountObjectPtr arr=disc2->getOffsetArr(f->getMesh()); + MEDCouplingAutoRefCountObjectPtr tmp=DataArrayInt::New(); + int trueNval=0; + for(const int *pt3=da4->begin();pt3!=da4->end();pt3++) + trueNval+=arr->getIJ(*pt3+1,0)-arr->getIJ(*pt3,0); + tmp->alloc(trueNval,1); + int *tmpPtr=tmp->getPointer(); + for(const int *pt3=da4->begin();pt3!=da4->end();pt3++) + for(int j=arr->getIJ(*pt3,0);jgetIJ(*pt3+1,0);j++) + *tmpPtr++=j; + arrTmp=f->getArray()->selectByTupleId(tmp->begin(),tmp->end()); + pt2=arrTmp->getConstPointer(); + } const MEDCouplingGaussLocalization& gl=f->getGaussLocalization(id); MEDlocalizationWr(fid,nomGauss,typmai3[(int)(*iter).getType()],mesh->getMeshDimension(),&gl.getRefCoords()[0],MED_FULL_INTERLACE, gl.getNumberOfGaussPt(),&gl.getGaussCoords()[0],&gl.getWeights()[0],MED_NO_INTERPOLATION, MED_NO_MESH_SUPPORT); - int nbOfEntity=f->getMesh()->getNumberOfCellsWithType((*iter).getType()); int nbOfValues=gl.getNumberOfGaussPt()*nbOfEntity; INTERP_KERNEL::AutoPtr fieldname=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE); MEDLoaderBase::safeStrCpy(f->getName(),MED_NAME_SIZE,fieldname,MEDLoader::_TOO_LONG_STR); - MEDfieldValueWithProfileWr(fid,fieldname,numdt,numo,dt,MED_CELL,typmai3[(int)(*iter).getType()],MED_COMPACT_PFLMODE, - MED_ALLENTITIES_PROFILE,nomGauss,MED_FULL_INTERLACE,MED_ALL_CONSTITUENT,nbOfEntity,(const unsigned char*)pt); + if((*iter).getCellIdPerType().empty()) + { + MEDfieldValueWithProfileWr(fid,fieldname,numdt,numo,dt,MED_CELL,typmai3[(int)(*iter).getType()],MED_COMPACT_PFLMODE, + MED_ALLENTITIES_PROFILE,nomGauss,MED_FULL_INTERLACE,MED_ALL_CONSTITUENT,nbOfEntity,(const unsigned char*)pt); + } + else + MEDfieldValueWithProfileWr(fid,fieldname,numdt,numo,dt,MED_CELL,typmai3[(int)(*iter).getType()],MED_COMPACT_PFLMODE, + profileName,nomGauss,MED_FULL_INTERLACE,MED_ALL_CONSTITUENT,nbOfEntity,(const unsigned char*)pt2); pt+=nbOfValues*nbComp; + offset2+=(*iter).getNbOfGeoElt(); } break; } @@ -2577,12 +2651,56 @@ void MEDLoaderNS::prepareCellFieldDoubleForWriting(const ParaMEDMEM::MEDCoupling { curType=(INTERP_KERNEL::NormalizedCellType)conn[*pt]; const int *pt2=std::find_if(pt+1,connI+nbOfCells,ConnReaderML(conn,(int)curType)); - if(!cellIdsPerType) - split.push_back(MEDLoader::MEDFieldDoublePerCellType(curType,0,nbComp,pt2-pt,0,0)); + int szOfChunk=std::distance(pt,pt2); + if(f->getTypeOfField()!=ON_GAUSS_PT) + { + if(!cellIdsPerType) + split.push_back(MEDLoader::MEDFieldDoublePerCellType(curType,0,nbComp,szOfChunk,1,0,0)); + else + { + split.push_back(MEDLoader::MEDFieldDoublePerCellType(curType,0,nbComp,szOfChunk,1,wCellIdsPT,0)); + wCellIdsPT+=szOfChunk; + } + } else { - split.push_back(MEDLoader::MEDFieldDoublePerCellType(curType,0,nbComp,pt2-pt,wCellIdsPT,0)); - wCellIdsPT+=std::distance(pt,pt2); + const MEDCouplingFieldDiscretizationGauss *disc=static_cast(f->getDiscretization()); + const DataArrayInt *arr=disc->getArrayOfDiscIds(); + MEDCouplingAutoRefCountObjectPtr da,daTmp1; + if(!cellIdsPerType) + da=arr->selectByTupleId2(std::distance(connI,pt),std::distance(connI,pt2),1); + else + { + daTmp1=DataArrayInt::New(); + daTmp1->useArray(const_cast(cellIdsPerType),false,CPP_DEALLOC,szOfChunk,1); + MEDCouplingAutoRefCountObjectPtr daTmp2=daTmp1->deepCpy(); + daTmp2->applyLin(1,std::distance(connI,pt)); + da=arr->selectByTupleId(daTmp2->begin(),daTmp2->end()); + } + std::vector differentIds; + std::vector parts=da->partitionByDifferentValues(differentIds); + std::vector< MEDCouplingAutoRefCountObjectPtr > partsAuto(parts.size()); + int jj=0; + for(std::vector::const_iterator it=parts.begin();it!=parts.end();it++,jj++) + partsAuto[jj]=parts[jj]; + jj=0; + for(std::vector::const_iterator it=parts.begin();it!=parts.end();it++,jj++) + { + if(!cellIdsPerType) + { + if(parts[jj]->getNumberOfTuples()==szOfChunk && parts[jj]->isIdentity()) + split.push_back(MEDLoader::MEDFieldDoublePerCellType(curType,0,nbComp,szOfChunk,1,0,0)); + else + split.push_back(MEDLoader::MEDFieldDoublePerCellType(curType,0,nbComp,parts[jj]->getNumberOfTuples(),1,parts[jj]->getConstPointer(),0)); + } + else + { + MEDCouplingAutoRefCountObjectPtr tmp=daTmp1->selectByTupleId(parts[jj]->begin(),parts[jj]->end()); + split.push_back(MEDLoader::MEDFieldDoublePerCellType(curType,0,nbComp,tmp->getNumberOfTuples(),1,tmp->getConstPointer(),0)); + } + } + if(!cellIdsPerType) + wCellIdsPT+=szOfChunk; } pt=pt2; } @@ -2637,7 +2755,7 @@ void MEDLoaderNS::writeFieldTryingToFitExistingMesh(const char *fileName, const throw INTERP_KERNEL::Exception(oss.str().c_str()); } MEDCouplingAutoRefCountObjectPtr m=MEDLoader::ReadUMeshFromFile(fileName,f->getMesh()->getName(),f2); - MEDCouplingAutoRefCountObjectPtr m2=MEDCouplingUMesh::MergeUMeshes(m,(MEDCouplingUMesh *)f->getMesh()); + MEDCouplingAutoRefCountObjectPtr m2=MEDCouplingUMesh::MergeUMeshes(m,static_cast(f->getMesh())); bool areNodesMerged; int newNbOfNodes; MEDCouplingAutoRefCountObjectPtr da=m2->mergeNodes(MEDLoader::_EPS_FOR_NODE_COMP,areNodesMerged,newNbOfNodes); diff --git a/src/MEDLoader/MEDLoader.hxx b/src/MEDLoader/MEDLoader.hxx index 61536db38..7fd9f43b8 100644 --- a/src/MEDLoader/MEDLoader.hxx +++ b/src/MEDLoader/MEDLoader.hxx @@ -66,17 +66,19 @@ class MEDLOADER_EXPORT MEDLoader class MEDFieldDoublePerCellType { public: - MEDFieldDoublePerCellType(INTERP_KERNEL::NormalizedCellType type, double *values, int ncomp, int ntuple, const int *cellIdPerType, const char *locName); + MEDFieldDoublePerCellType(INTERP_KERNEL::NormalizedCellType type, double *values, int ncomp, int nGeoElt, int nbi, const int *cellIdPerType, const char *locName); INTERP_KERNEL::NormalizedCellType getType() const { return _type; } int getNbComp() const { return _ncomp; } - int getNbOfTuple() const { return _ntuple; } - int getNbOfValues() const { return _ncomp*_ntuple; } + int getNbOfGeoElt() const { return _ngeo_elt; } + int getNbOfTuple() const { return _nbi*_ngeo_elt; } + int getNbOfValues() const { return _ncomp*_nbi*_ngeo_elt; } double *getArray() const { return _values; } const std::string& getLocName() const { return _loc_name; } const std::vector& getCellIdPerType() const { return _cell_id_per_type; } void releaseArray(); private: - int _ntuple; + int _ngeo_elt; + int _nbi; int _ncomp; double *_values; std::string _loc_name; diff --git a/src/MEDLoader/Swig/MEDLoaderTest3.py b/src/MEDLoader/Swig/MEDLoaderTest3.py index 1622b2980..194def721 100644 --- a/src/MEDLoader/Swig/MEDLoaderTest3.py +++ b/src/MEDLoader/Swig/MEDLoaderTest3.py @@ -1432,6 +1432,156 @@ class MEDLoaderTest(unittest.TestCase): # mfd.write(fname,2) pass + + def testGaussWriteOnPfl1(self): + fname="Pyfile49.med" + fname2="Pyfile50.med" + coords=DataArrayDouble([0.,0.,0.,1.,1.,1.,1.,0.,0.,0.5,0.5,1.,1.,0.5,0.5,0.],8,2) + mQ8=MEDCouplingUMesh("",2) ; mQ8.setCoords(coords) + mQ8.allocateCells(1) + mQ8.insertNextCell(NORM_QUAD8,range(8)) + mQ8.finishInsertingCells() + mQ4=MEDCouplingUMesh("",2) ; mQ4.setCoords(coords) + mQ4.allocateCells(1) + mQ4.insertNextCell(NORM_QUAD4,range(4)) + mQ4.finishInsertingCells() + mT3=MEDCouplingUMesh("",2) ; mT3.setCoords(coords) + mT3.allocateCells(1) + mT3.insertNextCell(NORM_TRI3,range(3)) + mT3.finishInsertingCells() + + tr=[[0.,4.],[2.,4.],[4.,4.],[6.,4.],[8.,4.],[10.,4.],[12.,4.],[14.,4.],[16.,4.],[18.,4.],[20.,4.],[0.,0.],[2.,0.], [0.,2.],[2.,2.],[4.,2.],[6.,2.],[8.,2.],[10.,2.],[12.,2.]] + ms=11*[mT3]+2*[mQ4]+7*[mQ8] + ms[:]=(elt.deepCpy() for elt in ms) + for m,t in zip(ms,tr): + d=m.getCoords() ; d+= t + pass + m=MEDCouplingUMesh.MergeUMeshes(ms) + m.setName("mesh") + m2=m[:13] ; m2.setName(m.getName()) + ### Use case 1 : Pfl on all tri3 and on all quad4. If we were on CELLS or GAUSS_NE no pfl were needed. But here 2 discs in tri3. + ### So here 2 pfls will be created (pfl_TRI3_loc_0 and pfl_TRI3_loc_1) + f=MEDCouplingFieldDouble.New(ON_GAUSS_PT,ONE_TIME) + f.setMesh(m2) + f.setTime(4.5,1,2) + da=DataArrayDouble(34) ; da.iota(3.) + f.setArray(da) + f.setName("fieldCellOnPflWithoutPfl") + f.setGaussLocalizationOnCells([0,1,2,3,4,5,6,7,8],[0.,0.,1.,0.,1.,1.],[0.3,0.3,0.7,0.7],[0.8,0.2]) + f.setGaussLocalizationOnCells([9,10],[0.,0.,1.,0.,1.,1.],[0.3,0.3,0.7,0.7,0.8,0.8],[0.8,0.07,0.13]) + f.setGaussLocalizationOnCells([11,12],[0.,0.,1.,0.,1.,1.,0.,1.],[0.3,0.3,0.7,0.7,0.8,0.8,0.8,0.8,0.8,0.8],[0.8,0.07,0.1,0.01,0.02]) + f.checkCoherency() + # + mm=MEDFileUMesh() + mm.setMeshAtLevel(0,m) + mm.write(fname,2) + # + f1ts=MEDFileField1TS.New() + pfl=DataArrayInt(range(13)) ; pfl.setName("pfl") + f1ts.setFieldProfile(f,mm,0,pfl) + f1ts.write(fname,0) + # + self.assertEqual(f1ts.getPfls(),('pfl_NORM_TRI3_loc_0', 'pfl_NORM_TRI3_loc_1')) + self.assertEqual(f1ts.getPflsReallyUsed(),('pfl_NORM_TRI3_loc_0', 'pfl_NORM_TRI3_loc_1')) + da1=DataArrayInt([0,1,2,3,4,5,6,7,8]) ; da1.setName("pfl_NORM_TRI3_loc_0") + self.assertTrue(f1ts.getProfile("pfl_NORM_TRI3_loc_0").isEqual(da1)) + da1=DataArrayInt([9,10]) ; da1.setName("pfl_NORM_TRI3_loc_1") + self.assertTrue(f1ts.getProfile("pfl_NORM_TRI3_loc_1").isEqual(da1)) + self.assertEqual(f1ts.getLocs(),('Loc_fieldCellOnPflWithoutPfl_NORM_TRI3_0', 'Loc_fieldCellOnPflWithoutPfl_NORM_TRI3_1', 'Loc_fieldCellOnPflWithoutPfl_NORM_QUAD4_2')) + self.assertEqual(f1ts.getLocsReallyUsed(),('Loc_fieldCellOnPflWithoutPfl_NORM_TRI3_0', 'Loc_fieldCellOnPflWithoutPfl_NORM_TRI3_1', 'Loc_fieldCellOnPflWithoutPfl_NORM_QUAD4_2')) + # + dataRead=MEDFileData.New(fname) + mRead=dataRead.getMeshes()[0] + f1tsRead=dataRead.getFields()[0][0] + f1tsRead.getFieldOnMeshAtLevel(ON_GAUSS_PT,0,mRead) + f2=f1tsRead.getFieldOnMeshAtLevel(ON_GAUSS_PT,0,mRead) + self.assertTrue(f.isEqual(f2,1e-12,1e-12)) + f2_bis=MEDLoader.ReadFieldGauss(fname,m.getName(),0,f.getName(),f.getTime()[1],f.getTime()[2]) + f2_bis.checkCoherency() + self.assertTrue(f.isEqual(f2_bis,1e-12,1e-12)) + # + MEDLoader.WriteField(fname2,f,True) + f2_ter=MEDLoader.ReadFieldGauss(fname2,m.getName(),0,f.getName(),f.getTime()[1],f.getTime()[2]) + self.assertTrue(f.isEqual(f2_ter,1e-12,1e-12)) + ## Use case 2 : Pfl on part tri3 with 2 disc and on part quad8 with 1 disc + f=MEDCouplingFieldDouble.New(ON_GAUSS_PT,ONE_TIME) + pfl=DataArrayInt([1,2,5,6,8,9,15,16,17,18]) ; pfl.setName("pfl2") + m2=m[pfl] ; m2.setName(m.getName()) + f.setMesh(m2) + f.setTime(4.5,1,2) + da=DataArrayDouble(35) ; da.iota(3.) + f.setArray(da) + f.setName("fieldCellOnPflWithoutPfl2") + f.setGaussLocalizationOnCells([0,1,3],[0.,0.,1.,0.,1.,1.],[0.3,0.3,0.7,0.7],[0.8,0.2]) + f.setGaussLocalizationOnCells([2,4,5],[0.,0.,1.,0.,1.,1.],[0.3,0.3,0.7,0.7,0.8,0.8],[0.8,0.07,0.13]) + f.setGaussLocalizationOnCells([6,7,8,9],[0.,0.,1.,0.,1.,1.,0.,1.,0.5,0.,1.,0.5,0.5,1.,0.,0.5],[0.3,0.3,0.7,0.7,0.8,0.8,0.8,0.8,0.8,0.8],[0.8,0.07,0.1,0.01,0.02]) + f.checkCoherency() + # + mm=MEDFileUMesh() + mm.setMeshAtLevel(0,m) + mm.write(fname,2) + f1ts=MEDFileField1TS.New() + f1ts.setFieldProfile(f,mm,0,pfl) + self.assertEqual(f1ts.getPfls(),('pfl2_NORM_TRI3_loc_0','pfl2_NORM_TRI3_loc_1','pfl2_NORM_QUAD8_loc_2')) + self.assertEqual(f1ts.getProfile("pfl2_NORM_TRI3_loc_0").getValues(),[1,2,6]) + self.assertEqual(f1ts.getProfile("pfl2_NORM_TRI3_loc_1").getValues(),[5,8,9]) + self.assertEqual(f1ts.getProfile("pfl2_NORM_QUAD8_loc_2").getValues(),[2,3,4,5]) + f1ts.write(fname,0) + dataRead=MEDFileData.New(fname) + mRead=dataRead.getMeshes()[0] + f1tsRead=dataRead.getFields()[0][0] + f1tsRead.getFieldOnMeshAtLevel(ON_GAUSS_PT,0,mRead) + f3=f1tsRead.getFieldOnMeshAtLevel(ON_GAUSS_PT,0,mRead) + f3.renumberCells([0,1,3,2,4,5,6,7,8,9]) + self.assertTrue(f.isEqual(f3,1e-12,1e-12)) + f3_bis=MEDLoader.ReadFieldGauss(fname,m.getName(),0,f.getName(),f.getTime()[1],f.getTime()[2]) + f3_bis.renumberCells([0,1,3,2,4,5,6,7,8,9]) + self.assertTrue(f.isEqual(f3_bis,1e-12,1e-12)) + # + MEDLoader.WriteField(fname2,f,True) + f3_ter=MEDLoader.ReadFieldGauss(fname2,m.getName(),0,f.getName(),f.getTime()[1],f.getTime()[2]) + f3_ter.renumberCells([0,1,3,2,4,5,6,7,8,9]) + self.assertTrue(f.isEqual(f3_ter,1e-12,1e-12)) + ## Use case 3 : no pfl but creation of pfls due to gauss pts + f=MEDCouplingFieldDouble.New(ON_GAUSS_PT,ONE_TIME) + f.setMesh(m) + f.setTime(4.5,1,2) + da=DataArrayDouble(60) ; da.iota(3.) + f.setArray(da) + f.setName("fieldCellWithoutPfl") + f.setGaussLocalizationOnCells([0,1,2,3,4,5,6,7,8],[0.,0.,1.,0.,1.,1.],[0.3,0.3,0.7,0.7],[0.8,0.2]) + f.setGaussLocalizationOnCells([9,10],[0.,0.,1.,0.,1.,1.],[0.3,0.3,0.7,0.7,0.8,0.8],[0.8,0.07,0.13]) + f.setGaussLocalizationOnCells([11,12],[0.,0.,1.,0.,1.,1.,0.,1.],[0.3,0.3,0.7,0.7,0.8,0.8,0.8,0.8,0.8,0.8],[0.8,0.07,0.1,0.01,0.02]) + f.setGaussLocalizationOnCells([13,14,15,17,18],[0.,0.,1.,0.,1.,1.,0.,1.,0.5,0.,1.,0.5,0.5,1.,0.,0.5],[0.3,0.3,0.7,0.7,0.8,0.8,0.8,0.8],[0.8,0.1,0.03,0.07]) + f.setGaussLocalizationOnCells([16,19],[0.,0.,1.,0.,1.,1.,0.,1.,0.5,0.,1.,0.5,0.5,1.,0.,0.5],[0.3,0.3,0.7,0.7,0.8,0.8],[0.8,0.1,0.1]) + f.checkCoherency() + mm=MEDFileUMesh() + mm.setMeshAtLevel(0,m) + f1ts=MEDFileField1TS.New() + f1ts.setFieldNoProfileSBT(f) + self.assertEqual(f1ts.getPfls(),('Pfl_fieldCellWithoutPfl_NORM_TRI3_0','Pfl_fieldCellWithoutPfl_NORM_TRI3_1','Pfl_fieldCellWithoutPfl_NORM_QUAD8_3','Pfl_fieldCellWithoutPfl_NORM_QUAD8_4')) + self.assertEqual(f1ts.getProfile("Pfl_fieldCellWithoutPfl_NORM_TRI3_0").getValues(),[0,1,2,3,4,5,6,7,8]) + self.assertEqual(f1ts.getProfile("Pfl_fieldCellWithoutPfl_NORM_TRI3_1").getValues(),[9,10]) + self.assertEqual(f1ts.getProfile("Pfl_fieldCellWithoutPfl_NORM_QUAD8_3").getValues(),[0,1,2,4,5]) + self.assertEqual(f1ts.getProfile("Pfl_fieldCellWithoutPfl_NORM_QUAD8_4").getValues(),[3,6]) + mm.write(fname,2) + f1ts.write(fname,0) + # + dataRead=MEDFileData.New(fname) + mRead=dataRead.getMeshes()[0] + f1tsRead=dataRead.getFields()[0][0] + f3=f1tsRead.getFieldOnMeshAtLevel(ON_GAUSS_PT,0,mRead) + f3.renumberCells([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,18,16,19]) + self.assertTrue(f.isEqual(f3,1e-12,1e-12)) + f3_bis=MEDLoader.ReadFieldGauss(fname,m.getName(),0,f.getName(),f.getTime()[1],f.getTime()[2]) + f3_bis.renumberCells([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,18,16,19]) + self.assertTrue(f.isEqual(f3_bis,1e-12,1e-12)) + # + MEDLoader.WriteField(fname2,f,True) + f3_ter=MEDLoader.ReadFieldGauss(fname2,m.getName(),0,f.getName(),f.getTime()[1],f.getTime()[2]) + f3_ter.renumberCells([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,18,16,19]) + self.assertTrue(f.isEqual(f3_ter,1e-12,1e-12)) + pass pass unittest.main() diff --git a/src/MEDMEMCppTest/CMakeLists.txt b/src/MEDMEMCppTest/CMakeLists.txt index ad869500a..423cc0fb7 100644 --- a/src/MEDMEMCppTest/CMakeLists.txt +++ b/src/MEDMEMCppTest/CMakeLists.txt @@ -26,6 +26,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/Bases ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/GaussPoints + ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/Geometric2D ) SET(MEDMEMCppTest_SOURCES diff --git a/src/MEDOP/cmp/CMakeLists.txt b/src/MEDOP/cmp/CMakeLists.txt index 165ca2d82..8579b38e5 100644 --- a/src/MEDOP/cmp/CMakeLists.txt +++ b/src/MEDOP/cmp/CMakeLists.txt @@ -50,7 +50,7 @@ SET(COMMON_LIBS ${SalomeGenericObj} medcoupling interpkernel - ${MED3_LIBS} + ${MED3_LIBS_C_ONLY} ${HDF5_LIBS} ${OMNIORB_LIBS} ${PLATFORM_LIBS} diff --git a/src/MEDOP/doc/models/medop.xmi b/src/MEDOP/doc/models/medop.xmi index 01758265f..9422c56f0 100644 --- a/src/MEDOP/doc/models/medop.xmi +++ b/src/MEDOP/doc/models/medop.xmi @@ -1,5 +1,5 @@ - + umbrello uml modeller http://uml.sf.net @@ -151,39 +151,39 @@ - - - + + + - - - + + + - - - + + + - - + + - + @@ -199,23 +199,23 @@ - + - - - + + + - - - + + + @@ -223,7 +223,7 @@ - + @@ -258,7 +258,7 @@ - + @@ -291,7 +291,7 @@ - + diff --git a/src/MEDOP/doc/sphinx/CMakeLists.txt b/src/MEDOP/doc/sphinx/CMakeLists.txt index 54da68859..cd0b113f9 100644 --- a/src/MEDOP/doc/sphinx/CMakeLists.txt +++ b/src/MEDOP/doc/sphinx/CMakeLists.txt @@ -20,21 +20,6 @@ IF(SPHINX_STATUS) SET(srcdir ${CMAKE_CURRENT_SOURCE_DIR}) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in ${CMAKE_CURRENT_BINARY_DIR}/conf.py @ONLY) - #FILE(GLOB MEDOP_DOC_RST "${CMAKE_CURRENT_SOURCE_DIR}/*.rst") - - #FOREACH(SRCFNAME ${MEDOP_DOC_RST}) - # GET_FILENAME_COMPONENT(FNAME ${SRCFNAME} NAME) - # CONFIGURE_FILE(${SRCFNAME} ${CMAKE_CURRENT_BINARY_DIR}/${FNAME} COPY_ONLY) - #ENDFOREACH(FNAME ${MEDOP_DOC_RST}) - - #FILE(MAKE_DIRECTORY _static) - #CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/_static/xmed.css ${CMAKE_CURRENT_BINARY_DIR}/_static/xmed.css COPY_ONLY) - - #FILE(GLOB MEDOP_DOC_PNG_RST "${CMAKE_CURRENT_SOURCE_DIR}/images/*.png") - #FOREACH(SRCFNAME ${MEDOP_DOC_PNG_RST}) - # GET_FILENAME_COMPONENT(FNAME ${SRCFNAME} NAME) - # CONFIGURE_FILE(${SRCFNAME} ${CMAKE_CURRENT_BINARY_DIR}/images/${FNAME} COPY_ONLY) - #ENDFOREACH(FNAME ${MEDOP_DOC_RST}) INSTALL(CODE "EXECUTE_PROCESS(COMMAND ${SPHINX_EXECUTABLE_TO_FIND} -c ${CMAKE_CURRENT_BINARY_DIR} -b html -d doctrees -D latex_paper_size=a4 ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/html)") diff --git a/src/MEDOP/doc/sphinx/Makefile.am b/src/MEDOP/doc/sphinx/Makefile.am index a28b03d44..2482d9030 100644 --- a/src/MEDOP/doc/sphinx/Makefile.am +++ b/src/MEDOP/doc/sphinx/Makefile.am @@ -71,27 +71,23 @@ html: RSTFILES= \ index.rst \ - xmed-specifications.rst \ - xmed-develguide.rst \ - xmed-userguide.rst + medop-specifications.rst \ + medop-develguide.rst \ + medop-userguide.rst # Files on the development of the prototype (version 2010) RSTFILES+=\ - xmed-prototype-overview.rst \ - xmed-prototype-develguide.rst \ - xmed-prototype-medmem.rst + medop-prototype-overview.rst \ + medop-prototype-develguide.rst \ + medop-prototype-medmem.rst # Files containing definitions and references RSTFILES+=\ - xmed-definitions.rst \ - xmed-references.rst \ - xmed-workingnotes-2010.rst \ - xmed-workingnotes-2011.rst \ - xmed-workingnotes-2012.rst - -# Files on annexe topics -RSTFILES+=\ - salomedoc.rst + medop-definitions.rst \ + medop-references.rst \ + medop-workingnotes-2010.rst \ + medop-workingnotes-2011.rst \ + medop-workingnotes-2012.rst EXTRA_DIST+= $(RSTFILES) diff --git a/src/MEDOP/doc/sphinx/_static/medop.css b/src/MEDOP/doc/sphinx/_static/medop.css new file mode 100644 index 000000000..150d01914 --- /dev/null +++ b/src/MEDOP/doc/sphinx/_static/medop.css @@ -0,0 +1,115 @@ +@import url("default.css"); + +body { + font-family: {{ 'Liberation', sans-serif }}; + font-size: 82%; + color: #000; + background-color: #fff; + margin-left: 28px; +} + +ul { + margin: 0 0 0 0; +} + +div.related { + background-color: #444; +} + +a, +div.sphinxsidebar h3 a, +div.sphinxsidebar a, +div.footer a { + color: #444; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + color: #000; +} + +div.sphinxsidebar ul { + font-size: 94%; + color: #000; +} + +div.sphinxsidebar input { + border-color: #444; +} + +div.document { + background-color: #f5f8e4; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + color: #000; + background-color: transparent; + border-bottom: 1px solid #444; +} + +div.footer { + color: #000; +} + +li.toctree-l2 { + font-size: 100%; +} + +li.toctree-l3 { + font-size: 100%; +} + +div.sphinxsidebarwrapper ul { + list-style-type: disc; + margin-top: 1px; + padding-left: 6px; +} + +div.sphinxsidebarwrapper h3 { + font-size: 100%; + font-weight: bold; +} + +div.body h1 { + font-size: 200%; +} +div.body h2 { + font-size: 160%; +} +div.body h3, div.body h4 { + font-size: 125%; +} + +div.body p.topic-title { + margin-bottom: 2px; + font-size: 100%; +} + +div.sphinxsidebar p { + color: #444; +} + +#introduction p > em { + text-align: right; + float: right; +} + +#introduction p { + font-size: 90%; + margin-bottom: 3px; +} + +#introduction #id2.docutils.footnote { + font-size: 70%; + margin-top: 25px; +} + +#introduction table.docutils.footnote { + font-size: 70%; + margin-top: 5px; +} diff --git a/src/MEDOP/doc/sphinx/_static/xmed.css b/src/MEDOP/doc/sphinx/_static/xmed.css deleted file mode 100644 index 150d01914..000000000 --- a/src/MEDOP/doc/sphinx/_static/xmed.css +++ /dev/null @@ -1,115 +0,0 @@ -@import url("default.css"); - -body { - font-family: {{ 'Liberation', sans-serif }}; - font-size: 82%; - color: #000; - background-color: #fff; - margin-left: 28px; -} - -ul { - margin: 0 0 0 0; -} - -div.related { - background-color: #444; -} - -a, -div.sphinxsidebar h3 a, -div.sphinxsidebar a, -div.footer a { - color: #444; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - color: #000; -} - -div.sphinxsidebar ul { - font-size: 94%; - color: #000; -} - -div.sphinxsidebar input { - border-color: #444; -} - -div.document { - background-color: #f5f8e4; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - color: #000; - background-color: transparent; - border-bottom: 1px solid #444; -} - -div.footer { - color: #000; -} - -li.toctree-l2 { - font-size: 100%; -} - -li.toctree-l3 { - font-size: 100%; -} - -div.sphinxsidebarwrapper ul { - list-style-type: disc; - margin-top: 1px; - padding-left: 6px; -} - -div.sphinxsidebarwrapper h3 { - font-size: 100%; - font-weight: bold; -} - -div.body h1 { - font-size: 200%; -} -div.body h2 { - font-size: 160%; -} -div.body h3, div.body h4 { - font-size: 125%; -} - -div.body p.topic-title { - margin-bottom: 2px; - font-size: 100%; -} - -div.sphinxsidebar p { - color: #444; -} - -#introduction p > em { - text-align: right; - float: right; -} - -#introduction p { - font-size: 90%; - margin-bottom: 3px; -} - -#introduction #id2.docutils.footnote { - font-size: 70%; - margin-top: 25px; -} - -#introduction table.docutils.footnote { - font-size: 70%; - margin-top: 5px; -} diff --git a/src/MEDOP/doc/sphinx/conf.py.in b/src/MEDOP/doc/sphinx/conf.py.in index 1127d1ba2..8259ef916 100644 --- a/src/MEDOP/doc/sphinx/conf.py.in +++ b/src/MEDOP/doc/sphinx/conf.py.in @@ -127,7 +127,7 @@ html_theme_options = { # The stylecheet file will be searched within the static path, while # the layout.html file will be searched within the template path # (Note that this parameter can't be used together with html_theme. Exclusive) -html_style = 'xmed.css' +html_style = 'medop.css' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -170,7 +170,7 @@ html_copy_source = True #html_file_suffix = '' # Output file base name for HTML help builder. -htmlhelp_basename = 'xmeddoc' +htmlhelp_basename = 'medopdoc' # Options for LaTeX output @@ -185,10 +185,10 @@ latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [ - ('index', 'xmed-alldoc.tex', 'Documentation du module XMED', 'G. Boulant', 'manual'), - ('xmed-specifications', 'xmed-specifications.tex', 'Module XMED - Specifications', 'G. Boulant', 'manual'), - ('xmed-develguide', 'xmed-develguide.tex', 'Module XMED - Guide de developpement', 'G. Boulant', 'manual'), - ('xmed-userguide', 'xmed-userguide.tex', 'Module XMED - Guide d\'utilisation', 'G. Boulant', 'manual') + ('index', 'medop-alldoc.tex', 'Documentation du module MED', 'G. Boulant', 'manual'), + ('medop-specifications', 'medop-specifications.tex', 'Module MED - Specifications', 'G. Boulant', 'manual'), + ('medop-develguide', 'medop-develguide.tex', 'Module MED - Guide de developpement', 'G. Boulant', 'manual'), + ('medop-userguide', 'medop-userguide.tex', 'Module MED - Guide d\'utilisation', 'G. Boulant', 'manual') ] # The name of an image file (relative to this directory) to place at the top of diff --git a/src/MEDOP/doc/sphinx/index.rst b/src/MEDOP/doc/sphinx/index.rst index 90fdc6b46..1989de788 100644 --- a/src/MEDOP/doc/sphinx/index.rst +++ b/src/MEDOP/doc/sphinx/index.rst @@ -1,12 +1,17 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - Documentation du module XMED -%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Documentation du module MED +%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Le module SALOME nommé XMED (pour eXtension MED) est l'espace de -développement des fonctions de manipulation de champs dans SALOME. Le -contenu de ce module est amené à intégrer le module MED pour former la -future version en préparation pour la version SALOME 7 de 2012. +Le module SALOME MED (pour Modèle d'Echange de Données) fournit la +bibliothèque MEDCoupling (bibliothèque C++ dédiée à la manipulation de +maillages et de champs conformes au modèle MED), ainsi qu'une +interface graphique pour la réalisation des opérations de manipulation +les plus usuelles. + +.. warning:: La partie interface graphique du module MED (composant + logiciel dénommé MEDOP) doit être considérée comme un + prototype pour la version SALOME6. Documentation principale ======================== @@ -14,9 +19,9 @@ Documentation principale .. toctree:: :maxdepth: 1 - xmed-specifications.rst - xmed-develguide.rst - xmed-userguide.rst + medop-specifications.rst + medop-develguide.rst + medop-userguide.rst Documentation du prototype 2010 =============================== @@ -27,9 +32,9 @@ analyses de conception (maquette 2010 sur base MEDMEM) .. toctree:: :maxdepth: 1 - xmed-prototype-overview.rst - xmed-prototype-develguide.rst - xmed-prototype-medmem.rst + medop-prototype-overview.rst + medop-prototype-develguide.rst + medop-prototype-medmem.rst Documentation annexe ==================== @@ -37,8 +42,7 @@ Documentation annexe .. toctree:: :maxdepth: 1 - xmed-references.rst - xmed-workingnotes-2010.rst - xmed-workingnotes-2011.rst - xmed-workingnotes-2012.rst - salomedoc.rst + medop-references.rst + medop-workingnotes-2010.rst + medop-workingnotes-2011.rst + medop-workingnotes-2012.rst diff --git a/src/MEDOP/doc/sphinx/medop-definitions.rst b/src/MEDOP/doc/sphinx/medop-definitions.rst new file mode 100644 index 000000000..cfd0bc148 --- /dev/null +++ b/src/MEDOP/doc/sphinx/medop-definitions.rst @@ -0,0 +1,88 @@ +.. AVERTISSEMENT: +.. Ce fichier contient les définitions globales à la documentation. Il +.. peut être inclu au moyen de la directive rst "include" pour +.. disposer des définitions dans le fichier qui fait l'inclusion. +.. Pour éviter de polluer les textes dans lequel ce fichier est inclu, +.. il est interdit de faire afficher du texte par ce document de +.. définition. + +.. REFERENCES DOCUMENTAIRES: +.. (les documents sont fournis dans le répertoire _static/documents) + +.. You can refer to this reference using the keyword: |REF_EDF_VCA_H-I2C-2009-03595-FR|_ +.. |REF_EDF_VCA_H-I2C-2009-03595-FR| replace:: H-I2C-2009-03595-FR: Manipulation de champs dans SALOME - Orientations générales +.. _REF_EDF_VCA_H-I2C-2009-03595-FR: _static/documents/20091218_EDF_VCANO_H-I2C-2009-03595-FR.pdf + +.. You can refer to this reference using the keyword: |REF_CEA_VBE_MEDMEM|_ +.. |REF_CEA_VBE_MEDMEM| replace:: Guide utilisateur de MED mémoire +.. _REF_CEA_VBE_MEDMEM: _static/documents/20070105_CEA_VBERGEAUD_GuideutilisateurMEDMEMOIRE.pdf + +.. You can refer to this reference using the keyword: |REF_EDF_GBO_WORKNOTE|_ +.. |REF_EDF_GBO_WORKNOTE| replace:: XMED: Notes de travail +.. _REF_EDF_GBO_WORKNOTE: _static/documents/20110309_XMED_scan_notes.pdf + +.. You can refer to this reference using the keyword: |REF_EDF_ELO_REM|_ +.. |REF_EDF_ELO_REM| replace:: XMED: Remarques E. Lorentz +.. _REF_EDF_ELO_REM: _static/documents/20110309_XMED_scan_remarques_ELORENTZ.pdf + +.. You can refer to this reference using the keyword: |REF_EDF_PRESMANIPCHP01|_ +.. |REF_EDF_PRESMANIPCHP01| replace:: Séminaire EDF-CEA de janvier 2010: manipulation de champs +.. _REF_EDF_PRESMANIPCHP01: _static/documents/20100129_MAN_seminaireEDF-CEA_all.pdf + +.. You can refer to this reference using the keyword: |REF_EDF_PRESMANIPCHP02|_ +.. |REF_EDF_PRESMANIPCHP02| replace:: Révue EDF-CEA: maquette de manipulation de champs +.. _REF_EDF_PRESMANIPCHP02: _static/documents/20101027_MAN_revueEDF-CEA.pdf + +.. You can refer to this reference using the keyword: |REF_EDF_PRESMANIPCHP03|_ +.. |REF_EDF_PRESMANIPCHP03| replace:: Séminaire EDF-CEA de mars 2011: manipulation de champs, maquette 2010 +.. _REF_EDF_PRESMANIPCHP03: _static/documents/20110310_seminaireEDF-CEA_maquetteXMED.pdf + +.. PRESENTATIONS: + +.. You can refer to this reference using the keyword: |REF_EDF_JUS2011_PDF|_ +.. |REF_EDF_JUS2011_PDF| replace:: JUS2011: outils de manipulation de champs +.. _REF_EDF_JUS2011_PDF: _static/presentations/20111115_JUS-2011/20111115_JUS2011_manipulation_de_champs.pdf + +.. You can refer to this reference using the keyword: |REF_EDF_JUS2011_OGV1|_ +.. |REF_EDF_JUS2011_OGV1| replace:: JUS2011: outils de manipulation de champs - Exemple 1 +.. _REF_EDF_JUS2011_OGV1: _static/presentations/20111115_JUS-2011/20111115_JUS2011_medop_exemple_1.ogv +.. You can refer to this reference using the keyword: |REF_EDF_JUS2011_OGV3|_ +.. |REF_EDF_JUS2011_OGV3| replace:: JUS2011: outils de manipulation de champs - Exemple 3 +.. _REF_EDF_JUS2011_OGV3: _static/presentations/20111115_JUS-2011/20111115_JUS2011_medop_exemple_3.ogv +.. You can refer to this reference using the keyword: |REF_EDF_JUS2011_OGV4|_ +.. |REF_EDF_JUS2011_OGV4| replace:: JUS2011: outils de manipulation de champs - Exemple 4 +.. _REF_EDF_JUS2011_OGV4: _static/presentations/20111115_JUS-2011/20111115_JUS2011_medop_exemple_4.ogv + + + +.. LIENS EXTERNES: +.. (l'accès nécessite le réseau intranet EDF et internet) + +.. You can refer to this reference using the keyword: |LINK_EDF_MEDDOC|_ +.. |LINK_EDF_MEDDOC| replace:: Modèle MED +.. _LINK_EDF_MEDDOC: http://med.der.edf.fr/logiciels/med-2.3.6/doc/html/modele_de_donnees.html + +.. You can refer to this reference using the keyword: |LINK_EDF_MEDFICHIERDOC|_ +.. |LINK_EDF_MEDFICHIERDOC| replace:: Documentation de MED fichier +.. _LINK_EDF_MEDFICHIERDOC: http://med.der.edf.fr/logiciels/med-2.3.6/doc + +.. You can refer to this reference using the keyword: |LINK_EDF_SALOME_MED__MED|_ +.. |LINK_EDF_SALOME_MED__MED| replace:: SALOME_MED::MED +.. _LINK_EDF_SALOME_MED__MED: http://nepal.der.edf.fr/pub/SALOME_userguide/MED5/doc/salome/tui/MED/interfaceSALOME__MED_1_1MED.html + +.. RENVOIES: + +.. You can refer to this reference using the keyword: |SEE_MEDMEM_CORBA| +.. |SEE_MEDMEM_CORBA| replace:: :ref:`L'interface CORBA SALOME_MED` + + +.. SNAPSHOTS: + +.. |XMED_SPECIFICATIONS_PDF| replace:: version pdf +.. _XMED_SPECIFICATIONS_PDF: _static/documents/xmed-specifications.pdf + +.. |XMED_DEVELGUIDE_PDF| replace:: version pdf +.. _XMED_DEVELGUIDE_PDF: _static/documents/xmed-develguide.pdf + +.. |XMED_USERGUIDE_PDF| replace:: version pdf +.. _XMED_USERGUIDE_PDF: _static/documents/xmed-userguide.pdf diff --git a/src/MEDOP/doc/sphinx/medop-develguide.rst b/src/MEDOP/doc/sphinx/medop-develguide.rst new file mode 100644 index 000000000..20d49c61a --- /dev/null +++ b/src/MEDOP/doc/sphinx/medop-develguide.rst @@ -0,0 +1,275 @@ +.. meta:: + :keywords: maillage, champ, manipulation, med, développement + :author: Guillaume Boulant + +.. include:: medop-definitions.rst + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Module MED: Guide de développement du composant MEDOP +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Le composant logiciel MEDOP est un élément du module MED. Il fournit +une interface utilisateur pour la manipulation de maillages et de +champs, composée d'une interface texte (TUI) et d'une interface +graphique (GUI). L'interface graphique constitue l'interface graphique +du module MED. + +Ce document est la documentation technique du composant MEDOP. Il +fournit les instructions à suivre pour installer le composant en vue +d'un travail de développement, puis décrit les éléments de conception. + +.. contents:: Sommaire + :local: + :backlinks: none + +Mise en place de l'espace de développement +========================================== + +Gestion de configuration du composant MEDOP +------------------------------------------- + +Le composant logiciel MEDOP est un package du module SALOME MED, +hébergé dans l'espace source au niveau du sous-répertoire +`src/MEDOP`. La gestion des fichiers sources est donc intégrée dans le +module SALOME MED. + +Organisation des sources du composant MEDOP +------------------------------------------- + +Le répertoire source `src/MEDOP` distingue les sous-répertoires +suivants: + +* cmp: package containing the SALOME components +* tui: package containing the python user interface +* gui: package containing the graphical user interface (the GUI part + of the MED module) +* res: resources files associated to the MEDOP package (icons, config + files, data files, ...) +* exe: additional executable programs that can be launched from the + MEDOP framework + +Construction du composant MEDOP +------------------------------- + +Intégré à la construction du module MED. Le composant MEDOP dépend de +MEDCoupling et MEDLoader uniquement. + +Exécution des tests unitaires du composant MEDOP +------------------------------------------------ + +Les tests unitaires peuvent être exécutés au moyen de scripts python +lancés depuis une session shell SALOME. Dans un nouveau shell, taper:: + + $ ./appli/runSession + [NS=mars:2810]$ python appli/lib/python2.6/site-packages/salome/xmed/test_medoperation.py + +L'exécution imprime un rapport détaillant le résultat pour chaque +fonction de test:: + + test_addition (__main__.MyTestSuite) ... ok + test_arithmetics (__main__.MyTestSuite) ... ok + test_composition (__main__.MyTestSuite) ... FAIL + test_litteral_equation (__main__.MyTestSuite) ... ok + test_modification_of_attributes (__main__.MyTestSuite) ... ok + test_unary_operations (__main__.MyTestSuite) ... ok + test_update_metadata (__main__.MyTestSuite) ... ok + +Les scripts de test sont: + +* ``test_medoperation.py``: tests des operations de champs telles + qu'elles sont mises en oeuvre depuis l'interface textuelle. +* ``test_xmed.py``: tests des composants CORBA mis en oeuvre + (``MEDDataManager`` et ``MEDCalculator``) + +Architecture du module XMED +=========================== + +Le module MED pour la manipulation de champs est composé de: + +* une bibliothèque de fonctions pour le traitement de données sur des + maillages et des champs conformes au modèle MED (package + MEDCoupling, MEDLoader et REMAPPER); +* une interface graphique pour la mise en oeuvre des cas standard de + manipulation de champs; +* une ensemble d'outils pour intervenir sur des fichiers au format + MED. + +Une bibliothèque de fonctions pour le traitement de données +----------------------------------------------------------- + +La figure ci-dessous montre la structure des paquets logiciels qui +constituent la bibliothèque: + +.. image:: images/medlayers.png + :align: center + +Elle comprend en particulier les paquets suivants: + +* MEDCoupling: qui décrit les structures de données pour porter les + maillages et les champs +* MEDLoader: qui fournit les fonctions de persistence sous forme de + fichiers au format MED (lecture et écriture). +* REMAPPER: + +Il est important de noter que MEDCoupling n'a aucune dépendance +logicielle autre que la bibliothèque C++ standard. Ceci permet +d'envisager son implantation dans un code de calcul ou un outil de +traitement sans tirer l'ensemble pré-requis de SALOME. + +Une interface graphique pour l'exécution des cas standard +--------------------------------------------------------- + + +Un ensemble d'outils pour le traitement de fichiers +--------------------------------------------------- + + +Description des composants +========================== + +MEDDataManager - Le gestionnaire des données de session +------------------------------------------------------- + +Le composant MEDDataManager s'occupe de fournir les données MED sur +demande des interfaces clientes, en particulier pour module de +pilotage fieldproxy.py. Ces données peuvent avoir plusieurs sources, +en général elle proviennent d'un fichier au format med contenant des +champs définis sur des maillages. Les données sont identifiées à la +lecture des métadonnées de description dans le fichiers med, puis les +valeurs des champs et les maillages support sont chargés au besoin. + +Le chargement des métadonnées de description se fait par la méthode:: + + addDatasource(const char \*filepath) + + + +Eléments d'implémentation +========================= + +Ecrire un service CORBA qui retourne une sequence de FieldHandler: + +.. code-block:: cpp + + MEDOP::FieldHandlerList * MyFunction(...) { + vector fieldHandlerList; + ... + + fieldHandlerList.push_back(fieldHandler); + + // Map the resulting list to a CORBA sequence for return: + MEDOP::FieldHandlerList_var fieldHandlerSeq = new MEDOP::FieldHandlerList(); + int nbFieldHandler = fieldHandlerList.size(); + fieldHandlerSeq->length(nbFieldHandler); + for (int i=0; iid] = fieldHandler; + + // >>> WARNING: CORBA struct specification indicates that the + // assignement acts as a desctructor for the structure that is + // pointed to. The values of the fields are copy first in the new + // structure that receives the assignement and finally the initial + // structure is destroyed. In the present case, WE WANT to keep + // the initial fieldHandler in the map. We must then make a deep + // copy of the structure found in the map and return the copy. The + // CORBA struct specification indicates that a deep copy can be + // done using the copy constructor. <<< + return new MEDOP::FieldHandler(*fieldHandler); + + + +ANNEXE A: Bug en cours +====================== + +TO FIX: + +* la composition d'opérations n'est pas possible (ex: 2*f1+f2) car + 2*f1 est indiqué comme non compatible (il semble qu'il n'ai pas la + reference correcte vers le maillage). +* le script de test test_medoperation.py plante si le module xmed n'a + pas été chargé avec des données chargées. + +ANNEXE B: Traçabilité avec le module XMED +========================================= + +Le module SALOME de nom XMED est l'espace de développement initial du +composant logiciel MEDOP, intégré aujourd'hui au module MED. Cette +annexe est la notice technique de ce module, qui reste disponible mais +qui n'est plus maintenu. + +Gestion de configuration du module XMED +--------------------------------------- + +Les sources du module (répertoire ``xmed``) sont archivés en dépôt de +configuration dans une base git du projet NEPAL. Ils peuvent être +récupérés au moyen de la commande:: + + $ git clone git@cli70rw.der.edf.fr:xom/xmed.git + +Cette commande installe un répertoire ``xmed`` contenant l'ensemble +des sources du module XMED. + +Le module XMED a pour pré-requis logiciel la plateforme SALOME: + +* SALOME version 6.1.3 (au moins) à télécharger à l'URL + http://pal.der.edf.fr/pal/projets/pal/releases/V6_1_3 +* On peut également utiliser une version dérivée comme SALOME-MECA 2010.1 +* Installer la plate-forme choisie selon les instructions fournies. + +Le module XMED utilise également une bibliothèque interne au projet +NEPAL, appelée XSALOME, et qui fournit une extension aux fonctions de +SALOME pour un usage de développement (XSALOME signifie eXtension +SALOME). Les sources de cette bibliothèque doivent être récupérés au +moyen de la commande:: + + $ git clone git@cli70rw.der.edf.fr:xom/xsalome.git + +Cette commande installe un répertoire ``xsalome`` contenant l'ensemble +des sources de la bibliothèque XSALOME. + +.. note:: La bibliothèque XSALOME n'est pas un module SALOME mais une + simple bibliothèque de fonctions qui complète ou rend plus facile + d'utilisation les fonctions de SALOME. Elle NE DOIT EN AUCUN CAS + être intégrée à d'autres projets que les projets internes NEPAL ou + MAILLAGE. Il s'agit en effet d'une bibliothèque de transition qui + héberge des développements destinés à être reversés dans la + plate-forme SALOME. Le contenu et les interfaces de XSALOME ne peut + donc être garanti sur le long terme. + +Installation et lancement de l'application +------------------------------------------ + +L'installation suppose qu'une version 6.1.3 de SALOME (ou plus) est +disponible et que le shell de travail est étendu avec l'environnement +de SALOME. En général, par des commandes de la forme:: + + $ . /where/is/salome/prerequis.sh + $ . /where/is/salome/envSalome.sh + +La compilation des modules xsalome et xmed suit le standard SALOME. La +bibliothèque xsalome est un prérequis à la compilation de xmed. Pour +cela, la variable d'environnement XSALOME_DIR doit être spécifiée pour +la configuration de la procédure de reconstruction de xmed:: + + $ export XSALOME_DIR= + +Aprés l'installation de xmed, il est possible de générer +automatiquement une application SALOME prête à l'emploi pour la +manipulation de champs:: + + $ /bin/salome/xmed/appligen/appligen.sh + +Cette commande génére un répertoire ``appli`` à l'emplacement où elle +est exécutée. Il reste à lancer l'application SALOME au moyen de la +commande:: + + $ ./appli/runAppli -k diff --git a/src/MEDOP/doc/sphinx/medop-prototype-develguide.rst b/src/MEDOP/doc/sphinx/medop-prototype-develguide.rst new file mode 100644 index 000000000..de2387b74 --- /dev/null +++ b/src/MEDOP/doc/sphinx/medop-prototype-develguide.rst @@ -0,0 +1,731 @@ +.. meta:: + :keywords: maillage, champ, manipulation, XMED + :author: Guillaume Boulant + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Démonstrateur XMED, documentation technique +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Cette note fait la synthèse des développements effectués pour le +maquettage des fonctions de manipulation de champs dans SALOME. Elle +présente les principes retenus en matière de conception, c'est-à-dire +concernant les mécanismes techniques sous-jacents, et en matière +d'ergonomie, c'est-à-dire concernant les modalités d'utilisation dans +l'environnement SALOME. + +Ces principes sont illustrés par des développements implantés dans le +module XMED, développé pour les besoins de l'analyse, et dans le +module MED distribué avec la plateforme SALOME. + +.. note:: la lecture de ce chapitre demande une connaissance de la + structure de classes du module MED, en particulier la distinction + entre les classes ``MEDMEM::*`` et les servants CORBA associés + (classe ``SALOME_MED::*``). + +.. contents:: Sommaire + :local: + :backlinks: none + +Principes directeurs +==================== + +Objectif et motivation +---------------------- + +L'objectif de maquettage est de trouver une architecture technique qui +permet d'exécuter le cas d'utilisation suivant: + +* Chargement d'un fichier med dans SALOME (a priori dans le module MED) +* Sélection graphique des champs de l'étude à mettre à disposition + dans la console utilisateur ("calculette" en mode texte qui + concraitement correspond à l'interface python de SALOME). +* Dans la calculette, exécution d'opérations algébriques (+,-,*,/) + entre champs avec possibilité d'utiliser des scalaires dans des + opérations de type transformation linéaire (y=ax+b ou y et x sont + des champs et a et b des scalaires). Opérations pow, sqrt. +* Possibilité de visualiser les champs produits avec VISU pour + contrôle des résultats. +* Possibilité d'exporter des champs produits dans un fichier med. + +Eléments de contexte +-------------------- + +Les opérations de manipulation de champs sont en grande partie +implémentées dans la bibliothèque MEDMEM. Pour illustration, le +fragment de code ci-dessous montre comment une addition de champ peut +être opérée en python: + +.. code-block:: python + + from libMEDMEM_Swig import MedDataManager + from xmed.helper import readMed, writeMed + + # Load the medmem data structure from a med file + med = readMed("/tmp/input.med") + # Then create a med data manager to deal with the fields data + dm = MedDataManager(med) + # Get the timestamps (dt,it)=(-1,-1) of the fields "testfield1" and "testfield2" + f1 = dm.getFieldDouble("testfield1",-1,-1) + f2 = dm.getFieldDouble("testfield2",-1,-1) + + # Create a new field as the sum of f1 and f2 + r = f1 + f2 + # And add this new field to the med data structure + med.addField(r) + + # Finally, write the whole data in an output med file + writeMed(med,"/tmp/output.med") + +Ceci montre que les champs peuvent être manipulés avec une interface +relativement ergonomique (une addition de deux champs f1 et f2 s'écrit +f1+f2) tant que l'on manoeuvre des objets MEDMEM purs (classes C++ du +package MEDMEM et wrapping python du package MEDMEM_SWIG). + +Par ailleurs, le fonctionnement actuel des modules SALOME qui +manoeuvrent des données MED est d'instancier les structures de données +MEDMEM au niveau de la partie serveur, c'est-à-dire au niveau des +servants CORBA hébergés dans le processus ``SALOME_Container``, et de +donner accés à ces données depuis l'étude SALOME au travers de +pointeurs CORBA. Ce choix d'architecture présente l'avantage de +centraliser au niveau serveur la gestion du cycle de vie des données +informatiques et de pouvoir distribuer des "poignées" pour manipuler +ces données depuis chaque point de l'application qui sait accéder au +bus CORBA, l'interface graphique en particulier. + + +Hypothèse de travail +-------------------- + +Compte-tenu de l'objectif de maquettage et des éléments de contexte +existant, on cherche une solution dans le cadre des hypothèses +de travail suivantes: + +* La manipulation des champs se fait dans l'environement graphique de + SALOME. +* Dans cet environnement, on souhaite pouvoir sélectionner + graphiquement les champs à considérer, puis manipuler ces champs + dans l'interface texte au moyen de variables python avec une syntaxe + aussi simple que celle définie dans le wrapping python de MEDMEM, + c'est-à-dire que pour faire l'addition de 2 champs f1 et f2, on veut + pouvoir écrire f1+f2. +* Les données MED sont physiquement dans la partie serveur de SALOME + et accessibles via des pointeurs CORBA (interface spécifiée dans + MED.idl). On exclu la recopie de données au niveau du client + graphique. + +Dans le cadre de ces hypothèses, la difficulté technique réside dans +la mise au point d'une interface de communication entre des variables +manipulées par l'utilisateur dans l'interface graphique (c'est-à-dire +dans le processus ``SALOME_SessionServer``) et des objets MEDMEM +instanciés dans le containeur des servants CORBA (c'est-à-dire dans le +processus ``SALOME_Container``). + + +Eléments de conception +====================== + + +Implantation technique +---------------------- + +Le diagramme ci-dessous représente l'organisation des principaux +paquets logiciels du module MED: + +.. image:: images/medmem-layers.png + :align: center + +Les cadres bleus représentent le lieu d'implantation des +développements effectués dans le module MED pour les besoins du +maquettage. On notera en particulier les interventions aux niveaux +suivants: + +* interfaces idl: ajout de l'interface MEDOP.idl +* package MEDMEM_I: ajout du servant SALOME_MED::MEDOP qui implémente + l'interface MEDOP.idl + +Architecture technique +---------------------- + +Les schéma ci-dessous représente les objets informatiques qui sont à +l'oeuvre pour la réalisation des opérations sur les champs: + +.. image:: /images/xmed-architecture.png + :align: center + :alt: Objets mis en oeuvre dans l'interface de manipulation de champs + +On distingue les objets suivants: + +* Une instance de ``MEDMEM::MED``, correspondant à la structure de donnée + MED chargée en mémoire. +* Des instances de ``MEDMEM::FIELD`` qui représentent les champs med + chargés en mémoire. +* Une instances de ``SALOME_MED::MED`` et des instances de + ``SALOME_MED::FIELD`` qui sont les servants CORBA respectivement de la + structure med et des champs qui lui sont associés et chargés en + mémoire. +* Une instance de ``SALOME_MED::MEDOP`` qui est le servant CORBA qui + centralise la mise en oeuvre des opérations de champs sur le serveur + ``SALOME_Container``. Le servant MEDOP détient en attribut une référence + sur la structure ``MEDMEM::MED``, ce qui lui permet d'accéder + directement aux champs ``MEDMEM::FIELD`` à partir de leur nom et du pas + de temps. +* Des instances de ``FieldProxy`` qui correspondent aux variables + manipulées au niveau de l'interface graphique et qui représentent + les champs. Une instance de FieldProxy possède détient les + références des servants ``SALOME_MED::MEDOP`` et + ``SALOME_MED::FIELD`` sous la forme de pointeurs CORBA de noms + ``medop_ptr`` et ``field_ptr`` respectivement. +* Il existe également une instance de ``MedProxy`` non représentée + dans ce diagramme. Cette instance correspond à une variable qui + permet de manipuler la structure med. + +.. note:: Les éléments apportés par la maquette sont les classes + ``SALOME_MED::MEDOP``, ``MedProxy`` et ``FieldProxy``. Les autres + éléments ont pu être modifiés légèrement pour les besoins de + l'intégration ou pour la correction de quelques bugs. + +Le cycle de vie de ces objets est le suivant. + +Pour ce qui concerne les instances de la structure ``MEDMEM::MED`` et +des champs ``MEDMEM::FIELD``, la création est faite au moment du +chargement du fichier med dans SALOME au moyen du module MED. A cette +occasion, les servants CORBA associés ``SALOME_MED::MED`` et +``SALOME_MED::FIELD`` sont créés et des références vers ces servants +sont publiés dans l'étude. Ils peuvent donc être sélectionnés par +l'utilisateur dans l'interface graphique. L'ensemble de ces données +préexiste à la manipulation de champs. + +Les objets ``SALOME_MED::MEDOP`` sont instanciés au sein du servant +``SALOME_MED::MED`` auquel ils sont associées. Le servant +``SALOME_MED::MED`` possède une référence sur la structure +``MEDMEM::MED`` et il la transmet à l'instance du servant +``SALOME_MED::MEDOP`` qu'il construit. L'opérateur MEDOP est donc +autonome par la suite pour manipuler les données MED, et les champs en +particulier. Le code python ci-dessous montre comment un opérateur med +``SALOME_MED::MEDOP`` peut être créé puis utilisé pour réaliser +l'addition de deux champs: + +.. code-block:: python + + import salome + salome.salome_init() + import SALOME_MED + + medComp = salome.lcc.FindOrLoadComponent("FactoryServer", "MED") + medObj = medComp.readStructFile("myfile.med",salome.myStudyName) + medOp = medObj.createMedOperator() + + f1 = medObj.getField("testfield1",-1,-1) + f2 = medObj.getField("testfield2",-1,-1) + + somme = medOp.add(f1,f2) + +Il est à noter qu'une instance de ``SALOME_MED::MEDOP`` est associé à +une instance unique de ``SALOME_MED::MED`` (et donc indirectement de +``MEDMED::MED``) pour toute la durée de son cycle de vie. Par contre, +un servant ``SALOME_MED::MED`` peut être associé à plusieurs servants +``SALOME_MED::MEDOP`` différents. Un servant ``SALOME_MED::MEDOP`` a +une référence directe sur la structure ``MEDMEM::MED`` et peut la +manoeuvrer pour demander des champs, faire des opérations avec ces +champs, ajouter le champs résultat à la structure et enfin retourner +un servant ``SALOME_MED::FIELD`` qui encapsule le champ résultat. + +Enfin, quelques éléments concernant la classe ``FieldProxy``. Une +instance de ``FieldProxy`` est un objet python qui peut être +manoeuvrée dans l'interpréteur SALOME et qui référence un champ MED +localisé sur le serveur ``SALOME_Container`` (par le mécanisme décrit +ci-dessus). C'est à ce niveau qu'on règle les détails d'ergonomie +d'usage (cf. paragraphe ci-après). La création d'un objet +``FieldProxy`` déclenche la création d'un opérateur med (instance de +``SALOME_MED::MEDOP``) qui lui est associé et dont il conserve la +référence CORBA en attribut (noté ``medop_ptr`` sur le diagramme). Cet +opérateur ``medop_ptr`` peut être requêter pour exécuter toutes les +opérations possibles sur ce champ, comme illustrer sur l'exemple +ci-dessus. + + +Rôle des objets proxy +--------------------- + +Dans le modèle d'architecture présenté ci-dessus, on introduit deux +types d'objets proxy: + +* Les objets de classe ``FieldProxy`` qui représentent des poignées de + manipulation des champs ``MEDMEM::FIELD`` physiquement instanciés + dans le container SALOME. +* Les objets de classe ``MedProxy`` qui représentent des poignées de + manipulation des structures ``MEDMEM::MED`` physiquement instanciées + dans le container SALOME. + +Elles sont instanciées dans l'interpréteur python SALOME pour +manipulation dans l'interface textuelle à partir de la donnée du +pointeur vers le servant ``SALOME_MED::MED`` et de l'identifiant du +champ (le nom du champ et le pas de temps défini par le numéro d'ordre +et le numéro d'iteration: + +.. code-block:: python + + import salome + salome.salome_init() + import SALOME_MED + + medComp = salome.lcc.FindOrLoadComponent("FactoryServer", "MED") + medObj = medComp.readStructFile("myfile.med",salome.myStudyName) + + from xmed import fieldproxy + from xmed import medproxy + + f1 = fieldproxy.getFieldFromMed(medObj, "testfield1", -1, -1) + f2 = fieldproxy.getFieldFromMed(medObj, "testfield2", -1, -1) + + field_somme = f1 + f2 + field_offset = f1 + 5.3 + +Dans cet exemple, les variables ``f1``, ``f2``, ``field_somme`` et +``field_offset`` sont des objets de classe ``FieldProxy``. Ils +correspondent aux variables physiquement manipulées par +l'utilisateur pour désigner les champs dans les opérations. + +Ces classes proxy sont conçues pour être le lieu d'implémentation de +l'interprétation des commandes utilisateur et donc de l'ergonomie +de manipulation des champs au niveau l'interface textuelle. Ce point +est développé :ref:`plus bas `. + +Programmation de l'interface textuelle +-------------------------------------- + +Dans le cadre de la maquette, l'interface de manipulation des champs +est l'interface textuelle python intégrée à SALOME. Dans la pratique, +l'utilisateur manipule des variables python qui correspondent à des +objets de classe ``FieldProxy`` équipées des fonctions requises et de +l'ergonomie nécessaire à la mise en oeuvre des opérations (voir +ci-dessus). + +Or, l'hypothèse de travail est que les données MED sont chargées dans +SALOME et publiées dans l'étude pour point d'accés depuis l'interface +graphique. L'utilisateur choisi un champs directement dans l'arbre +d'étude (ou dans une interface graphique dédiée) puis demande qu'il +soit mis à disposition dans l'interface python sous un nom de variable +à choisir. Les captures d'écran ci-dessous montre la séquence +graphique en images: + +.. |IMG_SELECT| image:: images/medop-gui-selectfield_scale.png +.. |IMG_ALIAS| image:: images/medop-gui-aliasfield_scale.png + ++---------------+---------------+ +| |IMG_SELECT| | |IMG_ALIAS| | ++---------------+---------------+ + +L'image de gauche montre la sélection du pas de temps, l'image de +droite la boîte de dialogue qui permet la saisie de l'alias avec +lequel le champs sera manipulé dans l'interface textuelle. La +validation de cette fenêtre doit mettre automatiquement le champ à +disposition dans l'interface python SALOME et sous le nom de variable +spécifié par l'alias saisi. + +Pour cela, il y a un couplage technique à programmer entre l'interface +graphique et l'interface textuelle python, avec en particulier la +transmission des pointeurs vers les servants CORBA mis en jeu dans la +sélection. + +Ce couplage est implanté au niveau de la classe MEDGUI.cxx du module +MED (où de la classe XMEDGUI.cxx du module XMED pour la maquette) qui +implémente l'interface graphique du module. Pour rappel, l'interface +graphique d'un module SALOME se présente sous la forme d'une classe +centrale de nom ``GUI`` et qui spécialise la classe +``SalomeApp_Module``. Cette classe possède une méthode ``getApp()`` +par laquelle on peut récupérer une instance de la console python +embarquée (this->getApp()->pythonConsole()). + +Le code suivant illustre l'envoie d'une commande python par ce +mécanisme. Dans cet example, on cherche à reconstituer dans le +contexte de la console python un pointer vers un objet med instancié +dans le contexte C++ de l'application graphique. Pour cela, on +communique la référence de l'objet sous la forme sérialisé (IOR pour +un objet CORBA): + +.. code-block:: cpp + + #include + #include + #include + #include + + // We suppose here that we have a CORBA object reference (object of + // type *_ptr or *_var), for example a SALOME_MED::MED object. + SALOME_MED::MED_ptr medObj = ... // anything to get this object + + // Get the IOR of this object + QString medIOR = SalomeApp_Application::orb()->object_to_string(medObj); + + PyConsole_Console * pyConsole = getApp()->pythonConsole(); + + QStringList commands; + commands+="import salome"; + commands+=QString("med=salome.orb.string_to_object(\"%1\")").arg(medIOR); + + QStringListIterator it(commands); + while (it.hasNext()) { + pyConsole->exec(it.next()); + } + +Le code réel de la maquette est basé sur ce principe et transmet à la +console python des lignes de commandes qui permettent de reconstruire: + +* un pointeur CORBA vers le servant ``SALOME_MED::MED`` associé au + champ sélectionné; +* une instance de ``FieldProxy`` qui correspond au champ sélectionné + et avec pour nom de variable la valeur de l'alias saisi dans + l'interface graphique. + +Au niveau du code C++ de la classe ``XMEDGUI.cxx``, cela se traduit +par la fabrication de la liste de commandes suivante pour envoie à la +console python par le mécanisme illustré plus haut: + +.. code-block:: cpp + + QStringList commands; + commands+="from xmed.fieldproxy import getFieldFromMed"; + commands+="from xmed.medproxy import getMedProxy"; + commands+=QString("if not dir().__contains__('med'): med = getMedProxy(\"%1\")").arg(medIOR); + commands+=QString("%1=getFieldFromMed(med,\"%3\",%4,%5)").arg(*alias).arg(fieldName).arg(orderIndex).arg(iterationIndex); + +Les variables ``medIOR``, ``fieldName``, ``orderIndex`` et +``iterationIndex`` sont construites à partir du champ sélectionné par +des techniques de programmation standard dans SALOME qu'on peut +examiner en détail dans la classe ``XMEDGUI`` (voir méthode +``XMEDGUI::LoadIntoPythonConsole()``). La variable ``alias`` est la +chaîne saisie par l'utilisateur dans la fenêtre de dialogue. + +Le point important à noter ici est que les données à transmettre +doivent être fournies sous forme de chaînes de caractères ou de types +simples. C'est pourquoi la référence au servant CORBA +``SALOME_MED::MED`` est transmise ici sous la forme de son IOR, +c'est-à-dire une chaîne de caractères qui permet l'identification de +l'objet au niveau du bus CORBA. + +Au niveau de la console python cela correspond à l'exécution des +commandes suivantes: + +.. code-block:: python + + from xmed.fieldproxy import getFieldFromMed + from xmed.medproxy import getMedProxy + + med = getMedProxy("IOR:010000001700000049444c3a53414c4f4d455f4d45442f4d45443a312e300000010000000000000064000000010102000e0000003133302e39382e37372e313733009e0a0e000000feadc4ca4c00003169000000001100000200000000000000080000000100000000545441010000001c00000001000000010001000100000001000105090101000100000009010100") + + f1=getFieldFromMed(med,"testfield1",-1,-1) + +Ce jeu d'instructions reconstitue un pointeur vers le servant CORBA +``SALOME_MED::MED`` à partir de son identifiant IOR (voir la fonction +``getMedProxy(...)``, puis crée une instance de ``FieldProxy`` +associée à ce servant (en fait associée au servant +``SALOME_MED::MEDOP`` créé sur demande par le servant +``SALOME_MED::MED``, voir la fonction ``getFieldFromMed(...)``). + +.. _develguide_execFieldOperation: + +Exécution des opérations sur le champs +-------------------------------------- + +Les variables définies dans l'interface textuelle pour désigner les +champs à manipuler sont des objets de classe ``FieldProxy``. + +Cette classe a une propriété remarquable, elle est construite sur un +design pattern de type "Proxy" qui pointe vers un servant +``SALOME_MED::FIELD``. Cela signifie que l'on ne peut pas accéder +directement au servant vers lequel il pointe, mais que l'on passe +systématiquement par une procédure de l'objet proxy qui fait "boîte +aux lettres": + +.. code-block:: python + + class FieldProxy: + + def __getattr__( self, name ): + """ + This method realizes the proxy pattern toward the servant + SALOME_MED::FIELD. + """ + return getattr( self.__field_ptr, name ) + +Ce pattern permet l'implémentation de pré-traitement et/ou de +post-traitement suivant le type d'accés que l'on cherche à faire. + +Il permet aussi et surtout de fournir un objet python qui présente +l'interface de ``SALOME_MED::FIELD`` dotée d'extentions adhoc pour les +operations de champs. Ici, python est ton ami, car il s'agit pour cela +d'équiper la classe ``FieldProxy`` des automatismes prévus nativement +par python pour les operations entre objets. En particulier, la +re-définition des fonctions internes ``__add__`` (opérateur addition), +``__sub__`` (opérateur soustraction), ``__mul__`` (opérateur +multiplication) et ``__div__`` (opérateur division) au sein de la +classe ``FieldProxy``, permet de prendre la main sur le comportement +des opérations algébriques et de définir une ergonomie sur mesure. Par +exemple, la méthode ``__add__`` peut gérer les variantes "f1+f2" +(ajout de deux variables de type FieldProxy) et "f1+5.3" (ajout d'un +réel à une variable de type FieldProxy): + +.. code-block:: python + + class FieldProxy: + + def __add__(self, operande): + """ + This can process the addition of two fields or the addition of + a scalar to a field. It depends weither the operande is a + FieldProxy or a simple scalar numerical value. + """ + if isinstance(operande, FieldProxy): + # The operande is an other field + otherField_ptr = operande.__field_ptr + rfield_ptr = self.__medOp_ptr.add(self.__field_ptr, otherField_ptr) + else: + # The operande is a scalar numerical value that must be + # considered as an offset in a linear transformation + factor = 1 + offset = operande + rfield_ptr = self.__medOp_ptr.lin(self.__field_ptr, factor, offset) + return FieldProxy(self.__med_ptr, rfield_ptr) + +Il est à noter que dans les deux cas de figure (opérande=champ ou +opérande=scalaire), la fonction délègue la réalisation concrète de +l'opération au servant ``SALOME_MED::MEDOP`` (identifié ici par +l'attribut ``self.__medOp_ptr`` et que l'on appelera l'*opérateur +MEDOP* dans la suite pour simplifier), mais n'appelle pas le même +service de calcul (l'addition entre champs dans le premier cas, +l'application d'une transformation linéaire de type y=factor*x+offset +dans le deuxième cas). + +Pour couvrir le cas des opérations algébriques, l'opérateur MEDOP +présentre l'interface suivante (cf. fichier ``MEDOP.idl`` qui définie +l'interface du servant ``SALOME_MED_MEDOP``): + +.. code-block:: cpp + + /*! Addition of the fields f1 and f2 ( f1+f2) */ + FIELD add(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception); + /*! Substraction of the fields f1 and f2 (f1-f2) */ + FIELD sub(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception); + /*! Multiplication of the fields f1 by f2 (f1*f2) */ + FIELD mul(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception); + /*! Division of the fields f1 by f2 (f1/f2) */ + FIELD div(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception); + /*! Power of the field f (f^power) */ + FIELD pow(in FIELD f, in long power) raises (SALOME::SALOME_Exception); + /*! Linear transformation of the field f (factor*f+offset) */ + FIELD lin(in FIELD f, in double factor, in double offset) raises (SALOME::SALOME_Exception); + /*! Dublication of the field f */ + FIELD dup(in FIELD f) raises (SALOME::SALOME_Exception); + +Cette interface est implémentée dans la classe C++ ``MEDOP_i`` du +module MED (voir fichier ``MEDMEM_MedOp_i.hxx`` du package +``MEDMEM_I``). C'est au sein des instances de cette classe que sont +réalisées les opérations et que sont produites physiquement les +données. Typiquement, les opérations présentées ici produisent un +champ ``MEDMEM::FIELD`` sur la base duquel elle fabrique un servant +``SALOME_MED::FIELD`` pour finalement retourner un pointeur CORBA sur +ce servant. + +Ce mécanisme global peut être étendu sans limitation à tout les types +d'opération qui sont envisagés dans les spécifications de manipulation +des champs dans SALOME. + + +Contrôle visuel des champs +-------------------------- + +Les illustrations ci-dessous montrent qu'une fonction de visalisation +est implémentée dans la maquette pour permettre le contrôle visuel +d'un champ au moyen d'une représentation 3D (une carte spatiale du +module du champ dans l'exemple implémenté par défaut): + +.. |IMG_VISU| image:: images/medop-gui-visufield_scale.png +.. |IMG_RESULT| image:: images/medop-gui-result_scale.png + ++---------------+---------------+ +| |IMG_VISU| | |IMG_RESULT| | ++---------------+---------------+ + +Cette fonction répond au besoin de contrôle interactif des résultats +produits par les opérations de manipulation de champs. + +Il s'agit là d'un usage classique de SALOME, dans lequel on demande au +module VISU de faire une représentation 3D d'un champ spécifié par la +donnée du servant ``SALOME_MED::FIELD`` qui lui est associé +(représenté par la variable ``field_ptr`` dans l'exemple ci-dessous): + +.. code-block:: python + + import salome + import VISU + + visuComp = salome.lcc.FindOrLoadComponent("FactoryServer", "VISU") + visuComp.SetCurrentStudy(salome.myStudy) + + # Then we can import the specified field in the VISU module. This + # creates an study entry in the VISU folder. + result = visuComp.ImportMedField(field_ptr) + + meshName = field_ptr.getSupport().getMesh().getName() + fieldName = field_ptr.getName() + iterNumber = field_ptr.getIterationNumber() + scalarmap = visuComp.ScalarMapOnField(result, + meshName, + visuEntityType, + fieldName, + iterNumber) + +Dans ce jeu d'instructions donné pour exemple (non fonctionnel, en +particulier à cause de la non définition de la variable +``visuEntityType``, voir remarque plus bas), le composant VISU +désigné ici par la variable ``visuComp`` va chercher les données du +champ en interrogeant le servant ``SALOME_MED::FIELD`` transmis en +argument de la fonction ``ImportMedField``, puis produit une +représentation de type "scalarmap". + +.. note:: Compte-tenu des propriétés de la classe FieldProxy décrites + plus haut conférées par le pattern "Proxy", on peut transmettre ici + aussi bien le servant CORBA que l'instance du proxy (la fonction + ``ImportMedField`` n'y verra que du feu). + +Le code complet et fonctionnel de la fonction d'affichage est dans le +corps du module python ``fieldproxy.py`` sous la forme d'une fonction +de nom ``visuField``. Il convient de noter que cette fonction doit +établir une correspondance entre le type des entités tel que défini +dans MED et dans VISU: + +.. code-block:: python + + medEntityType = field_ptr.getSupport().getEntity() + if (medEntityType == SALOME_MED.MED_CELL): + visuEntityType = VISU.CELL + elif (medEntityType == SALOME_MED.MED_NODE): + visuEntityType = VISU.NODE + + +Export des résultats de calcul +------------------------------ + +Tous les champs produits à l'occasion des opérations entre objets +``FieldProxy`` sont automatiquement ajoutés à la structure med à +laquelle is sont associés. Une convention d'attribution des noms est +implémentée de sorte que par défaut aucune précision n'est demandée à +l'utilisateur. + +La structure med peut être manipulée au moyen de la variable ``med`` +créée dans l'interface textuelle comme une instance de la classe +``MedProxy``. La classe ``MedProxy`` fournit un objet qui présente +l'interface du servant ``SALOME_MED::MED`` étendue de quelques +fonctions utilitaires pour la gestion et le contrôle des données. + +En particulier, la sauvegarde de la structure dans un fichier est +automatisée par la méthode ``save(medfilename)``: + +.. code-block:: python + + med = medproxy.MedProxy(medObj) + med.save("/tmp/output.med") + +Cette méthode s'occupe de définir un driver d'écriture et de procéder +à l'enregistrement des données de la structure med (les maillages, les +champs présents au départ et tous les champs produits depuis la +lecture initiale). + +Limitations +=========== + +L'implémentation de la maquette limite l'usage des opérations aux cas +de figure suivants: + +* Seules les operations entre champs qui partagent le même support med + sont possibles. Ceci est une contrainte imposé par la conception + actuelle de MEDMEM. +* Le résultat d'une opérations est calculé sur toutes les composantes + et tout le domaine de définition des champs en opérande. Cette + deuxième contrainte est juste parce que les usages plus fin, + notemment avec la notion de domaine de définition, n'a pas encore + été exéminée à ce jour. +* Le nom d'un champ produit par une opération ne correspond pas au nom + de la variable python par laquelle on le réceptionne et on le + manipule. Le nom est attribué par une convention (ceci n'est pas + vraiment une limitation mais une caractéristique à connaître). + +On note également les restriction techniques suivantes: + +* Les données MEDMEM sont supposées être chargées par le composant MED + puis référencées dans l'étude SALOME (comme c'est fait aujourd'hui + par le module MED). +* Dans certain cas, python n'est pas ton ami. Pour que les opérateur + de la classe ``FieldProxy`` soient pris en considération dans les + opérations sur les champs, il est indispensable que le premier + opérande d'une opération unitaire soit un champ (objet de classe + ``FieldProxy``). Par exemple: "field_offset = field + 5.3" + fonctionne alors que "field_offset = 5.3 + field" ne fonctionne pas + car python tente de traiter la situation au moyen de la fonction + ``__add__`` de la classe ``float`` (qui n'est pas modifiable). + + +Notice informatique +=================== + +Gestion de configuration +------------------------ + +Les développements décrits dans ce chapitre sont répartis entre les +modules MED et XMED (développé pour l'occasion). Cette séparation est +faite par soucis de clarté et d'efficacité de développement, mais les +éléménts du module XMED ont vocation à intégrer le module MED dans la +mesure où les propositions techniques sont retenues pour le +développement à venir. + +Le code source du module XMED peut être récupérés par la commande +suivante:: + + $ svn co svn://nepal.der.edf.fr/FIELD/XMED_SRC/trunk XMED_SRC + +Le pré-requis est la plate-forme SALOME version 5.1.4 (ou plus) +équipée au minimum des modules KERNEL, GUI, MED (branche BR_medop) et +VISU. Pour récupérer la branche BR_medop du module MED, taper la +commande:: + + $ cvs -d :pserver:anonymous@cvs.opencascade.com:2401/home/server/cvs/MED co -r BR_medop MED_SRC + +La configuration de référence est: + +* XMED: révision svn 41 +* MED: tag cvs BR_medop_20101025 + +Moyens de tests +--------------- + +Plusieurs types de tests unitaires sont définis (reste à les +automatiser proprement): + +* Test des servants et utilitaires de manipulation python: + + - Dans XMED, package xmed/tests, utiliser le script + ``test_medoperation.py`` dans un interpréteur python lancé dans + une session shell SALOME. Ce script prépare des variables de test + et fournit des fonctions de test unitaire (à exécuter ou pour s'en + inspirer). Après avoir lancé SALOME via une application virtuelle, + on peut taper:: + + $ /runSession + [NS=venus:2810] $ python -i test_medoperation.py + >>> + + - Ceci permet de tester en particulier l'interface ``MedOp`` et son + utilisation dans le module python ``fieldproxy.py``. + +* Test des classes MEDMEM: + + - Test de MEDMEM::MedDataManager dans ``MEDMEM_MedDataManager_test.cxx`` + +Un fichier de test basique (mais néanmoins suffisant) de nom +``tesfield.med`` est fourni avec les sources dans le répertoire +``/resources/datafiles`` et dans l'installation au niveau du +répertoire ``/share/salome/resources/xmed/datadir``. Il +contient deux champs ``testfield1`` et ``testfield2`` définis sur un +pas de temps unique (dt,it=-1,-1). Ces champs définissent des valeurs +par éléments (MED_CELL). diff --git a/src/MEDOP/doc/sphinx/medop-prototype-medmem.rst b/src/MEDOP/doc/sphinx/medop-prototype-medmem.rst new file mode 100644 index 000000000..2302f7b70 --- /dev/null +++ b/src/MEDOP/doc/sphinx/medop-prototype-medmem.rst @@ -0,0 +1,513 @@ +.. meta:: + :keywords: maillage, champ, MED, MEDMEM + :author: Guillaume Boulant + +.. include:: medop-definitions.rst + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Note de travail concernant l'utilisation de MEDMEM +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Le module MED de SALOME comporte plusieurs composants d'intérêt pour +la manipulation de champs: + +* la bibliothèque MEDMEM qui fournit une interface de programmation + pour manoeuvrer une structure MED +* le module CORBA SALOME_MED qui matérialise le composant SALOME + (serveur corba) du module MED +* l'interopérabilité avec le module VISU qui permet la visualisation + des champs manipulés dans MED + +Les sections ci-après donnent quelques éclairages techniques sur ces +différents aspects. Les sources de démonstration peuvent être +récupérés depuis le dépôt svn:: + + $ svn export svn://nepal.der.edf.fr/OM/manifield/trunk manifield + $ svn export svn://nepal.der.edf.fr/FIELD/demofield/trunk demofield + +.. contents:: Sommaire + :local: + :backlinks: none + +Présentation synthétique de MED +=============================== + +MED désigne un modèle conceptuel pour décrire des données de type +éléments finis (éléments finis, volumes finis et éléments +discrets). Dans l'usage courant, il permet la description et l'échange +des données de calcul de type maillages et champs. La documentation +complète peut être trouvée à l'URL suivantes: + +* |LINK_EDF_MEDDOC|_ (version 2.3). + +On distingue deux implémentations informatiques de ce modèle: + +* MED fichier: qui permet la lecture et l'écriture de données depuis + un fichier au format med. Les opérations de lecture/écriture sont + atomiques (pas de chargement de la structure de données globale). +* MED mémoire (noté MEDMEM): qui permet le chargement en mémoire d'une + image de la structure de données MED contenue dans un fichier au + format med. Les opérations peuvent être atomiques ou + globales. + +On notera simplement ici que MEDMEM utilise MED fichier pour les +opérations de lecture/écriture et que MED fichier est indépendant de +MED mémoire. La documentation complète de MED fichier peut être +trouvée à l'URL suivante: + +* |LINK_EDF_MEDFICHIERDOC|_ + +La bibliothèque MEDMEM +====================== + +Le modèle de classes MEDMEM est structuré autour des notions de MESH +(les maillages), de SUPPORT (le profil des entités) et de FIELD (les +champs). Ces notions reprennent en partie des concepts du modèle +MED. Le diagramme ci-dessous présente les classes principales: + +.. image:: images/med-uml-main_60pc.png + :align: center + +Le conteneur de plus haut niveau dans MEDMEM est la classe MED. La +figure ci-dessous indique qu'une instance MED peut être associée à +plusieurs maillage et plusieurs champs. Par contre un champ donné ne +peut être associé qu'à un seul maillage (par l'intermédiaire du +support). Plusieurs champs peuvent être associés au même maillage. La +forme la plus courante est d'ailleurs une instance composé d'un +maillage unique sur lequel sont définis plusieurs champs. + +On peut avoir également des configurations plus complexes, comme par +exemple un maillage unique, plusieurs champs définis sur ce maillage +mais avec des supports différents, par exemple parce que les valeurs +sont définies sur des entités de maillage différentes (les éléments +pour un champ, les noeuds pour un autre, ...):: + + field1->support1->mesh + field2->support2->mesh + field3->support3->mesh + +On observe: + +* 2 champs U et V doivent avoir le même support (au sens informatique + du terme) pour pouvoir être en argument d'une opération (sinon + exception). Il faudrait accepter qu'il soit informatiquement + différent et vérifier la conformité conceptuelle. +* Cette contrainte peut se comprendre car physiquement les données + sont stockées dans un vecteur qui couvre toutes les mailles. Le + support est le seul masque de lecture pour établir la correspondance + avec les positions dans le maillage et il est donc important qu'une + cohérence soit assurée. + +Les objets champs (FIELD) et maillage (MESH) +-------------------------------------------- + +Un objet MED permet d'accéder aux différentes informations concernant +les objets MESH, SUPPORT et FIELD, mais il ne permet pas d'accéder aux +données physiques associées à ces objets (les valeurs des composantes +pour les champs, les mailles et leur connectivité pour les +maillages). L'accès aux données physiques est du ressort des objets +spécifiques MESH, SUPPORT et FIELD. + +Un objet MED peut être créé intégralement en mémoire. L'usage plus +fréquent est de l'initialiser à partir de la donnée d'un fichier +med. Pour cela, l'objet MED doit être associé à un driver +d'entrée/sortie branché sur le fichier (``testfilename`` dans +l'exemple): + +.. code-block:: cpp + + MED *myMed = new MED; + MED_MED_RDONLY_DRIVER *driverIn = new MED_MED_RDONLY_DRIVER(testfilename, myMed); + driverIn->open(); + driverIn->readFileStruct(); + driverIn->close(); + +A l'occasion de la fonction readFileStruct, la structure interne de +l'objet MED est enrichie des informations concernant les objets MESH, +SUPPORT et FIELD contenu dans le fichier. En particulier un +dictionnaire des champs (variable map interne) est initialisé est +contient l'ensemble des objets ``FIELD_`` préchargés (i.e. avec les +méta-données uniquement). Chaque objet ``FIELD_`` ainsi préchargé est +autonome pour être chargé sur demande. On peut alors requêter l'objet +MED pour obtenir un champ particulier (spécifié par son nom +``fieldname`` dans l'exemple): + +.. code-block:: cpp + + FIELD *field = (FIELD *)myMed->getField(fieldname, dt, it); + +Puis le champ qui lui est associé doit être physiquement chargé pour +permettre la mise à jour du support: + +.. code-block:: cpp + + MESH * mesh = myMed->getMesh(field); + mesh->read(); + myMed->updateSupport(); + +Pour enfin charger les valeurs des composantes du champ: + +.. code-block:: cpp + + field->read(); + +La numérotation des éléments de maillage +---------------------------------------- + +Les éléments qui composent un maillage sont caractérisés par: + +* Le type d'entité de l'élément, à choisir dans la liste + ``MED_EN::medEntityMesh``, qui contient en particulier ``MED_NODE``, + ``MED_FACE``, ``MED_CELL``. +* Le type de géométrie de l'élément, à choisir dans la liste + ``MED_EN::medGeometryElement``, qui contient en particulier + ``MED_NONE``, ``MED_TRIA3``, ..., ``MED_ALL_ELEMENTS``. + +Les éléments sont numérotés par un indice relatif à la catégorie +géométrique à laquelle ils appartiennent. Ainsi, si le modèle est +composé de Na arrêtes et Nf faces de type géométrique MED_QUAD4, alors +ces faces sont numérotées de 1 à Nf dans le modèle MED (et de manière +persistente dans le fichier med). De même, les arrêtes sont numérotées +de 1 à Na. Une numérotion globale implicite existe sur les éléments, +elle consiste à parcourir l'ensemble des types géométriques dans +l'ordre de définition du modèle de données. Ainsi, si le modèle +contient uniquement les Na arrêtes et les Nf faces, alors l'indice +global de la première face est Na+1. + +.. note:: Des exemples de code sont disponibles dans le package ``demofield``, fichier ``python/pybasicfields/MEDMEM_tester.py``. + + +Binding python de MEDMEM +------------------------ + +Les classes du package ``MEDMEM`` (package du module ``MED`` qui +implémentent les structures de données C++ de MED mémoire) produisent +la bibliothèque ``libmedmem.so``. Cette ensemble de classes est en +partie mis à disposition de l'interface python grace à une couche de +liaison (binding Python-C++) générée par le logiciel SWIG à partir +d'un fichier de description d'interface ``libMEDMEM_Swig.i`` (dans le +package source ``MEDMEM_SWIG``). + +Ce fichier d'interface doit être mis à jour dés lors qu'une évolution +des interfaces publiques des classes C++ MEDMEM est faite ou qu'une +nouvelle classe est créée (du moins si l'on souhaite profiter de ces +évolutions dans l'interface python). + +Cette mise à jour nécessite de prendre soin au transfert des +structures de données entre les espaces python et C++. En particulier, +l'utilisation des template de classe pour décrire les champs typés en +C++ appelle une précaution de codage particulière de l'interface +SWIG. + +Pour exemple, le fragment de code ci-dessous, extrait du fichier +``libMEDMEM_Swig.i``, montre comment déclarer la nouvelle classe +``MedDataManager`` dans l'interface: + +.. code-block:: cpp + + #include "MEDMEM_MedDataManager.hxx" + + class MedDataManager + { + public: + ~MedDataManager(); + void printFieldDouble(FIELD * field); + + %extend { + MedDataManager(char * fileName) + { + return new MedDataManager(string(fileName)); + } + MedDataManager(MED * med) + { + return new MedDataManager(med); + } + + %newobject getFieldDouble(const char * fieldName, const int dt, const int it); + FIELD * getFieldDouble(const char * fieldName, const int dt, const int it) + { + return (FIELD *) self->getFieldDouble(string(fieldName), dt, it); + } + } + + }; + + +Utilisation de MEDMEM pour la manipulation de champs +---------------------------------------------------- + +Des opérations de manipulation de champs sont disponibles dans la +bibliothèque MEDMEM standard est peuvent être utilisées dans +l'interface python. Les quelques lignes suivantes illustrent l'usage +qu'on peut en faire pour exécuter l'addition de deux champs sur tout +leur espace de définition et pour un pas de temps donné: + +.. code-block:: python + + from libMEDMEM_Swig import MedDataManager + from xmed.helper import readMed, writeMed + + # Load the medmem data structure from a med file + med = readMed("/tmp/input.med") + # Then create a med data manager to deal with the fields data + dm = MedDataManager(med) + # Get the timestamps (dt,it)=(-1,-1) of the fields "testfield1" and "testfield2" + f1 = dm.getFieldDouble("testfield1",-1,-1) + f2 = dm.getFieldDouble("testfield2",-1,-1) + + # Create a new field as the sum of f1 and f2 + r = f1 + f2 + # And add this new field to the med data structure + med.addField(r) + + # Finally, write the whole data in an output med file + writeMed(med,"/tmp/output.med") + +.. note:: Cet exemple de code requiert les évolutions de MEDMEM + opérées dans la branche BR_medop (pour disposer de la classe + MedDataManager en particulier) et le package python ``xmed`` qui + fournit quelques fonctions utilitaires pour manoeuvrer les données + med (ce package est dans le module XMED et sera probablement à + terme intégré au module MED). + +Des limitations existent aujourd'hui pour ce type de manipulations: + +* les champs doivent partager le même support MED, c'est-à-dire être + décrit sur le même maillage et sur les mêmes entités de ce + maillage. +* ... + + +Remarque sur l'implémentation C++ +--------------------------------- + +A noter l'usage de plusieurs formes d'arguments pour les fonctions: + +* passage des arguments par valeur ``myfunction(A a);`` +* passage des arguments par référence ``myfunction(A& a);`` +* passage des arguments par pointeur ``myfunction(A* a);`` + +Le passage des arguments par référence est une facilité d'écriture +pour éviter de passer un pointeur tout en évitant la récopie des +données de la variable. + +.. _xmed-medmem_corbainterface: + +L'interface CORBA SALOME_MED +============================ + +Implémentation du composant MED et des servants SALOME_MED::\* +-------------------------------------------------------------- + +Le composant MED est un servant CORBA qui permet la manipulation de +données MEDMEM dans l'environnement SALOME. Le composant peut fournir +des pointeurs vers des instances de l'interface SALOME_MED (objets +SALOMEMED::MED, SALOME_MED_FIELD, ...). Ces instances sont des +servants CORBA qui résident dans le container et qui encapsulent les +données MEDMEM. + +Le schéma ci-dessous représente les éléments informatiques qui +composent l'architecture CORBA du module MED: + +.. image:: images/medmem-corba-layers.png + :align: center + +Les structures MEDMEM (données physiques) et SALOME_MED (wrapping +CORBA) fonctionnent différement en ce qui concerne le chargement des +données: + +* Dans MEDMEM, les données sont chargées à la demande (fonctions read + des objets) et aucune gestion n'est assurée. En particulier l'appel + à read alors que la donnée est déjà chargée conduit à une levée + d'exception. C'est à l'utilisateur de MEDMEM de prendre en charge ce + type de gestion. +* Dans SALOME_MED, les données sont chargées à la création de + l'instance SALOME_MED::MED. Les maillages ainsi que les champs et + leurs données sont chargés à ce moment là et gérés dans une table de + type HashMap au niveau de la structure SALOME_MED::MED. Cette + structure remplie dés lors des fonction de gestion. L'appel à + SALOME_MED::MED.getField(...) ne charge pas les données mais renvoie + un pointeur SALOME_MED::FIELD_ptr sur les données chargées à + l'initialisation (ATTENTION, cette fonction est bugguée dans la + branche principale -> Fix dans la branche BR_medop). + +Une gestion intermédiaire peut être envisagée: le chargement à la +demande géré dans une ou plusieurs tables de champs (une pour chaque +type de valeur numérique). Une implémentation de ce type de gestion +est illustré dans la classe ``MedDataManager`` du package MEDMEM qui prend +en charge ce comportement pour les structures de données MED (en +particulier les champs). + +Utilisation du composant MED +---------------------------- +Le module SALOME MED fournit un module CORBA appelé SALOME_MED. Les +interfaces de ce module CORBA sont spécifiées par les fichiers idl +suivants: + +* le fichier + [http://nepal.der.edf.fr/pub/SALOME_userguide/MED5/doc/salome/tui/MED/MED_8idl.html + ``MED.idl``] qui décrit les interfaces des objets manipulés par le + module SALOME_MED. On trouve en particulier les objets MESH, SUPPORT + et FIELD. +* le fichier + [http://nepal.der.edf.fr/pub/SALOME_userguide/MED5/doc/salome/tui/MED/MED__Gen_8idl.html + ``MED_Gen.idl``] qui décrit les interfaces du composant SALOME + (c'est-à-dire le composant chargé par la commande + ``FindOrLoadComponent("FactoryServer", "MED")`` du + lyfeCycleCorba). On trouve: + + - l'interface ``MED_Gen_Driver`` qui hérite de SALOMEDS::Driver + pour l'implémentation des services généraux des composants SALOME + (persistance hdf, dump) + - l'interface ``MED_Gen`` qui hérite des interfaces + ``Engines::Component`` et ``MED_Gen_Driver`` pour + l'implémentation des services spécifiques du composant MED. + +L'implémentation de ces interfaces est faites au niveau de différents +packages des sources du module MED: + +* Le package ``MEDMEM_I`` qui fournit l'implémentation C++ des + interfaces décrites par le fichier ``MED.idl``; +* Le package ``MED`` qui fournit l'implémentation C++ des interfaces + décrites par le fichier ``MED_Gen.idl``, et qui correspond à la + partie composant classique d'un module SALOME. +* Le package ``MedCorba_Swig`` qui fournit une interface swig + générée à partir de l'implémentation C++ de ``MEDMEM_I`` et + ``MED`` + +L'utilisation peut être illustrée au moyen d'exemples python (i.e. qui +utilise l'interface swig fournie par MedCorba_Swig). Après l'import +d'amorce systématique: + +.. code-block:: python + + import salome + salome.salome_init() + + import SALOME_MED + from libSALOME_Swig import * + +On peut charger le composant SALOME MED: + +.. code-block:: python + + medComp=salome.lcc.FindOrLoadComponent("FactoryServer", "MED") + +grâce auquel les services de chargement de la structure MED peuvent +être invoqués. Par exemple, les commandes suivantes chargent toute la +structure MED dans l'étude salome passée en argument: + +.. code-block:: python + + filePathName = "myfile.med" + medComp.readStructFileWithFieldType(filePathName,salome.myStudyName) + +Ce deuxième exemple charge la structure MED mais ne place pas le résultat dans l'étude: + +.. code-block:: python + + filePathName = "myfile.med" + medObj = medComp.readStructFile(filePathName,salome.myStudyName) + +On récupère à la place un objet de classe |LINK_EDF_SALOME_MED__MED|_ +qui permet une utilisation assez semblable (mais différente on le +verra plus bas) à MEDMEM: + +.. code-block:: python + + fieldIdx = 1 # WRN maybe there is no field of idx=1 + iterationIdx = 0 + fieldName = medObj.getFieldNames()[fieldIdx] + dtitfield = medObj.getFieldIteration(fieldName,iterationIdx) + it = dtitfield[0] + dt = dtitfield[1] + fieldObj = medObj.getField(fieldName,it,dt) + nbOfFields = medObj.getNumberOfFields() + fieldNames = medObj.getFieldNames() + + mesh = fieldObj.getSupport().getMesh() + +.. note:: + Observations en vrac: + + * Un FIELD_i possède un champ de type ``MEDMEM::FIELD_`` qui représente + le champ informatique réel (objet MEDMEM). + * FIELD_i::fieldMap variable static de type map qui semble gérer + les différentes instances de FIELD_i (~pattern factory). Cette + map peut être requétée au moyen d'un indice de type long appelé + corbaIndex. + * Quand on crée un FIELD_i par le constructeur d'argument + ``MEDMEM::FIELD_``, le ``MEDMEM::FIELD_`` est ajouté dans la map avec + incrément du corbaIndex + * La fonction FIELD_i::read(i) redirige vers la fonction read(i) du + ``MEDMEM::FIELD_`` associé + * A CONFIRMER: Il semble que les fonctions de chargement + ``readStructFile*()`` charge toutes les données du fichier med, + alors qu'en MEDMEM seules les meta-données sont chargées. + * A CONFIRMER: il semble que le chargement d'une structure MED + CORBA peut se faire sans passer par le composant (cf. l'interface + de MED) + +Interface avec le module VISU +============================= + +Des interactions sont possibles entre MED et VISU à partir du moment +où les données med sont gérées dans l'étude, c'est-à-dire sous la +forme d'objets SALOME_MED (voir ci-dessus) publiés dans l'étude. Les +deux conditions sont aujourd'hui nécessaires (objet corba + publié +dans l'étude) mais il semble que ce ne soit lié qu'à un choix +d'interface VISU (la fonction ``ImportMed`` en particulier) qui peut +a priori être modifié. A CONFIRMER. + +L'exemple de code ci-dessous (en python, mais il peut être transposé à +une implémentation C++) montre par exemple comment envoyer au module +VISU une requête de visualisation d'un champs hébergé par le module +MED (en fait, les données sont gérées au travers d'un objet corba +SALOME_MED "délocalisé" et qui a été référencé dans l'étude dans la +catégorie du composant MED). Les importations standard (salome, +SALOME_MED, ...) sont supposées avoir été faites au préalable (voir +les exemples précédents): + +.. code-block:: python + + # Load the med structure using MED + medComp=salome.lcc.FindOrLoadComponent("FactoryServer", "MED") + filePathName = "myfile.med" + medComp.readStructFileWithFieldType(filePathName,salome.myStudyName) + + # Get the VISU component + import VISU + visuComp = salome.lcc.FindOrLoadComponent("FactoryServer", "VISU") + visuComp.SetCurrentStudy(salome.myStudy) + + # Get the sobject associated to the med object named "Med" + aSObject = salome.myStudy.FindObject("Med") + isPresent, medSObj = aSObject.FindSubObject(1) + + # Finally, import the med sobject in VISU + result = visuComp.ImportMed(medSObj) + +Il est possible de d'aller plus loin et par exemple de déclencher +l'affichage d'une scalarmap d'un champ spécifique pour une itération +particulière (voir la fonction +``TEST_SALOMEMED_requestToVisu_scalarmap`` du fichier +``SALOMEMED_tester.py`` fourni dans les sources d'exemple). + +Liens complémentaires: + +* http://nepal.der.edf.fr/pub/SALOME_userguide/VISU_V5_1_3/doc/salome/gui/VISU La documentation utilisateur en ligne du module VISU + + +Notes en vrac +============= + +Questions: + +* Comment obtenir le nom du fichier med à partir d'une structure med? +* Peut-on imaginer un moyen de fournir l'objet MEDMEM::MED à partir de + la donnée de l'objet CORBA SALOME_MED::MED? + +Remarques: + +* A part, les opérations arithmétiques (+,-,*,/), aucune opération + n'est définie. diff --git a/src/MEDOP/doc/sphinx/medop-prototype-overview.rst b/src/MEDOP/doc/sphinx/medop-prototype-overview.rst new file mode 100644 index 000000000..c571c6e6f --- /dev/null +++ b/src/MEDOP/doc/sphinx/medop-prototype-overview.rst @@ -0,0 +1,95 @@ +.. meta:: + :keywords: maillage, champ, manipulation, XMED + :author: Guillaume Boulant + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Démonstrateur XMED, vue d'ensemble +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Le module XMED est un espace d'expérimentation pour le développement +des opérations de manipulation de champs. Il complète des +développements intégrés directement dans le module MED et gérés dans +la branche CVS BR_medop. + +Une maquette est au point pour illustrer les propositions en matière +d'ergonomie d'utilisation et en matière d'architecture technique. La +maquette permet de réaliser des cas d'utilisation de la forme: + +* Chargement d'un fichier med dans le module MED (ou publication par + un code de calcul). +* Sélection graphique des champs de l'étude à mettre à disposition + dans la console utilisateur ("calculette" en mode texte qui + concraitement correspond à l'interface python de SALOME). +* Dans la calculette, exécution d'opérations algébriques (+,-,*,/) + entre champs avec possibilité d'utiliser des scalaires dans des + opérations de type transformation linéaire (y=ax+b ou y et x sont + des champs et a et b des scalaires). Egalement quelques fonctions + mathématiques standard applicables sur des champs (pow, sqrt). +* Possibilité de visualiser les champs produits avec VISU +* Possibilité d'exporter des champs produits dans un fichier med + +La figure ci-dessous montre le résultat d'une séquence d'utilisation +dans laquelle les champs "testfield1" et "testfield2" ont été +sélectionnés dans l'arbre d'étude pour être utilisés dans la console +textuelle sous les noms de variables f1 et f2. L'image montre le +contrôle visuel du résultat de l'opération f1+f2-(f1-f2)^2 tapée en +ligne de commande: + +.. image:: images/medop-gui-result.png + :align: center + +La séquence ci-après montre le cas d'utilisation complet en +images: + +1. Sélection d'un champs sur un pas de temps dans l'arbre d'étude +2. Saisie d'un nom de variable (alias) pour manipuler ce champ. Par + défaut, le nom du champ est proposé (``testfield1`` ici). Dans + l'exemple, l'utilisateur remplace par l'alias ``f1``. +3. Contrôle visuel du champ ``testfield1`` manipulé par sa variable + ``f1`` au moyen de la commande ``f1.visu()`` +4. Chargement du champ ``testfield2`` sous le nom ``f2``, exécution de + l'opération ``f1+f2-(f1-f2)^2`` et contrôle visuel du résultat, + récupéré ici dans une variable de nom ``result``. + +.. |IMG_SELECT| image:: images/medop-gui-selectfield_scale.png +.. |IMG_ALIAS| image:: images/medop-gui-aliasfield_scale.png +.. |IMG_VISU| image:: images/medop-gui-visufield_scale.png +.. |IMG_RESULT| image:: images/medop-gui-result_scale.png + ++---------------+---------------+ +| |IMG_SELECT| | |IMG_ALIAS| | ++---------------+---------------+ +| |IMG_VISU| | |IMG_RESULT| | ++---------------+---------------+ + +La solution technique est construite sur les principes suivants: + +* Les données MEDMEM sont physiquement chargées par le composant MED, + c'est-à-dire dans le processus ``Container`` de SALOME, et sont + référencées dans l'étude SALOME. +* Les opérations sont physiquement des opérations entre objets MEDMEM + purs qui ont lieu dans le composant MED. +* Les opérations sont pilotées par des objets proxy python instanciés + dans la console TUI puis manipulés par l'utilisateur. Ces objets + proxy savent accéder aux objets MEDMEM au travers de leur interface + CORBA. + +Ainsi, l'architecture technique est construite pour pouvoir travailler +sur des données MEDMEM pur en partant de pointeurs CORBA manoeuvrés +depuis des objets python dans l'interface textuelle de +SALOME. L'effort principal a donc porté sur la mise au point de +l'interface technique qui permet de lier des variables représentant +les champs au niveau du GUI (techniquement, la calculette est +l'interpréteur python embarqué dans le GUI, étendu de quelques +fonctions pour la manipulation de champs), alors que les données +MEDMEM sont physiquement disponibles uniquement au niveau des +composants CORBA (et les opérations implémentées dans MEDMEM +uniquement). + +Pour le moment, la maquette est limitée à des operations entre champs +qui partagent le même support med (contrainte de MEDMEM) et le +résultat est calculé sur toutes les composantes et tout le domaine de +définition du champs (cette deuxième contrainte est juste parce que +les extentions n'ont pas encore été examinées). Enfin, le support de +gestion des données est supposé être l'étude SALOME et la structure +MED qui y est publiée. diff --git a/src/MEDOP/doc/sphinx/medop-references.rst b/src/MEDOP/doc/sphinx/medop-references.rst new file mode 100644 index 000000000..9be8cdc5f --- /dev/null +++ b/src/MEDOP/doc/sphinx/medop-references.rst @@ -0,0 +1,28 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +ANNEXE: Références documentaires +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +.. include:: medop-definitions.rst + +Documents de référence: + +* |REF_EDF_VCA_H-I2C-2009-03595-FR|_ - Valérie Cano - décembre 2009 +* |REF_CEA_VBE_MEDMEM|_ - Vincent Bergeaud - janvier 2007 +* |LINK_EDF_MEDDOC|_ - documentation en ligne (EDF) + +Présentations: + +* |REF_EDF_PRESMANIPCHP01|_ - Valérie Cano, Guillaume Boulant - janvier 2010 +* |REF_EDF_PRESMANIPCHP02|_ - Guillaume Boulant - octobre 2010 +* |REF_EDF_PRESMANIPCHP03|_ - Guillaume Boulant - mars 2011 +* Présentation à la Journée des Utilisateurs de SALOME de 2011 (JUS2011): + + - |REF_EDF_JUS2011_PDF|_ - Anthony Geay (CEA), Guillaume Boulant - novembre 2011 + - |REF_EDF_JUS2011_OGV1|_ + - |REF_EDF_JUS2011_OGV3|_ + - |REF_EDF_JUS2011_OGV4|_ + +Notes de travail: + +* |REF_EDF_GBO_WORKNOTE|_ - Guillaume Boulant - novembre 2010 +* |REF_EDF_ELO_REM|_ - Eric Lorentz - novembre 2010 diff --git a/src/MEDOP/doc/sphinx/medop-specifications.rst b/src/MEDOP/doc/sphinx/medop-specifications.rst new file mode 100644 index 000000000..09ca88cd2 --- /dev/null +++ b/src/MEDOP/doc/sphinx/medop-specifications.rst @@ -0,0 +1,916 @@ +.. meta:: + :keywords: maillage, champ, manipulation, med + :author: Guillaume Boulant + +.. include:: medop-definitions.rst + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Module MED: Spécifications fonctionnelles et techniques +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Ce texte présente les spécifications informatiques pour le +développement d'un module de manipulation de champs qui répond à +l'expression de besoins formulée dans le cahier des charges +|REF_EDF_VCA_H-I2C-2009-03595-FR|_. + +.. contents:: Sommaire + :local: + :backlinks: none + +Description des cas d'application de référence +============================================== + +Plusieurs cas d'applications métier sont identifiés pour piloter le +développement du module de manipulation de champs: + +* **Analyser et post-traiter le résultat d'un calcul**. C'est l'usage + principal qui consiste typiquement à créer des champs comme le + résultat d'*opérations mathématiques* dont les opérandes sont des + champs et des scalaires. On compte également dans cette catégorie + les *opérations de restriction* qui permettent d'extraire puis + utiliser une partie d'un champs, c'est-à-dire de créer un champ + comme la restriction d'un autre champ à une partie de son domaine de + définition (certaines composantes, certains pas de temps, limitation + à un groupe de mailles). +* **Comparer des champs issus d'un calcul paramétrique**. Il s'agit + d'une variante du cas précédent qui consiste à mesurer et visualiser + les variations entre des champs issues de sources de données + différentes (différents fichiers med). +* **Préparer les conditions aux limites d'une calcul**. Il s'agit de + pouvoir initialiser un champ sur un maillage ou un groupe de + mailles, c'est-à-dire créer un champ de toute pièce sur un + support spatial donné, par exemple par la donnée d'une fonction + mathématique qui donne les valeurs des composantes en fonction des + coordonnées spatiales. +* **Gérer des données de calcul**. Il s'agit typiquement de pouvoir + rassembler au sein d'un même fichier med des champs et des maillages + issues de différentes sources de données, et/ou créés au travers des + cas d'application présentés ci-dessus. + +Modèle conceptuel des données +============================= + +On rappelle ici les concepts utilisés dans le module et les modalités +d'utilisation de ces concepts. Le point de vue est celui de +l'utilisateur du module de manipulation de champs. Il s'agit +essentiellement pour le moment d'éclaircir l'ergonomie d'usage sur le +plan conceptuel, avant d'aborder la déclinaison en spécifications +techniques pour lesquelles les particularités du modèle MED devront +être intégrées à la réflexion. + +Concept de champ +---------------- + +Le concept central est celui de *champ*, c'est-à-dire une grandeur +physique exprimée sur un domaine spatial D. La grandeur peut être de +type scalaire (une température), de type vectorielle (une vitesse) ou +de type tensorielle (les contraintes). En un point de l'espace, elle +se définie donc par la donnée d'une ou plusieurs valeurs numériques +appelées les *composantes* (1 pour un champ scalaire, 3 pour un champ +vectoriel 3D, 6 pour un champ tensoriel symétrique 3D). + +.. note:: Une pratique courante au niveau des codes est de stocker + plusieurs grandeurs physiques différentes dans un même champs med + (au sens informatique du terme). Par exemple, le champ + électromagnétique à 6 composantes, plus le champ de température + scalaire peuvent techniquement être stockés dans un même champs med + à 7 composantes. C'est pourquoi, le module de manipulation de + champs doit fournir des fonctions de restrictions qui permettent + d'extraire certaines composantes pour former la grandeur physique à + étudier. Dans la suite du document, on part du principe que l'on + peut se ramener dans tous les cas au cas d'un champ homogène tel + que défini plus haut. + +Dans le cadre d'un modèle numérique discret, les valeurs du champ sont +exprimées pour un nombre fini de positions, qui correspondent à des +lieux particuliers du maillage. Suivant la nature des modèles de +calcul, les valeurs peuvent être données par cellule, par face, par +noeud, aux points de gauss, ... + +Ainsi, un champ discret est un objet dont les valeurs peuvent être +lues selon les dimensions suivantes: + +* *La position p dans l'espace*, caractérisée par le type de l'élément + de maillage support et son numéro identifiant +* *La composante c*, caractérisée par son indice (jusqu'à 6 + composantes dans les modèles physiques envisagés) + +L'évolution d'un champ dans le temps peut être exprimée sous la forme +d'une série temporelle, c'est-à-dire une séquence de champs donnés +pour des instants discrets. Aussi, si l'on manipule un champ qui varie +dans le temps, l'accès aux valeurs introduit une dimension +supplémentaire: + +* *Le temps t*, caractérisé par un numéro de pas de temps + (correspondant en général à une étape du calcul qui a produit le champ). + +.. note:: Il s'agit là d'une représentation conceptuelle standard dont + le |LINK_EDF_MEDDOC|_ fait une expression détaillée. En + particulier, la position p est déterminée par la donnée du type + d'élément support (valeurs aux noeuds, aux mailles, aux noeuds par + éléments, aux points de gauss) et de l'indice de cet élément. En + général, le type d'éléments support est résolu à l'initialisation + et l'indice peut suffire au repérage dans les algorithmes. Le temps + t est déterminé par un numéro d'itération, qui peut éventuellement + être complété par un numéro d'ordre. Le cas des points de gauss + ajoute un cran de complexité dans la mesure où il faut repérer + l'entité géométrique (maille, face, arrête) puis le point de gauss + de cette entité. A noter que dans le modèle MED, le concept de + série temporelle de champ n'est pas explicitement définie et + l'accès à des valeurs à différents instants t1 et t2 nécessite le + chargement des champs ``F1=F(t1)`` et ``F2=F(t2)``. + +Par convention, on utilisera par la suite les notations: + +* **U(t,p,c)** pour désigner la valeur de la composante c d'un champ U + à la position p et prise à l'instant t; +* **U(t,p,:)** pour signifier que l'on manipule l'ensemble de toutes + les composantes; +* **U(t,:,c)** pour signifier que l'on manipule le domaine de + définition spatial complet. + +Dans une grande majorité des cas d'usage on travaille à temps t fixé +et sur un domaine spatiale prédéfini. Aussi on utilisera également la +notation à deux arguments ``U(:,:)`` ou tout simplement ``U`` (dès +lors qu'il n'y a pas ambiguïté) pour désigner un champ complet et Uc +pour désigner la composante c du champ avec c=1..6. + +Concept d'opération +------------------- +Le deuxième concept à préciser est la notion d'*opération*. Une +opération dans le présent contexte est l'application d'un opérateur +sur un ou plusieurs champs pour produire une grandeur de type champ ou +de type valeur numérique. + +Par exemple, la formule ``W=OP(U,V)`` indique que le champ W est formé +à partir des champs U et V en arguments d'une fonction OP. Dans le cas +d'une opération algébrique comme l'addition (cf. :ref:`Spécification +des opérations`, le résultat attendu par défaut +est que pour chaque instant t, chaque position p et chaque composante +c, on a ``W(t,p,c)=U(t,p,c)+V(t,p,c)`` (que l'on peut noter également +``W(:,:,:)=U(:,:,:)+V(:,:,:)`` compte-tenu de la convention présentée +plus haut). Ce n'est cependant pas une règle et l'utilisateur peut +très bien manoeuvrer les champs en détaillant et mixant les +composantes (par exemple ``W(:,:,3)=5+U(:,:,1)*V(:,:,2)``), ou encore +ne travailler que sur un domaine spatial et/ou temporel particulier +(cf. |REF_EDF_VCA_H-I2C-2009-03595-FR|_ §5.4.1). + +On formalise donc le concept d'opération par les propriétés suivantes: + +* L'opérateur peut produire un champ (par exemple la somme de deux + champs W=sum(U,V)=U+V), une valeur numérique (par exemple la moyenne + spatiale d'un champ m=smoy(U)) ou une valeur logique (par exemple le + test d'égalité de deux champs b=isequal(U,V)); +* L'opérateur peut être paramétré par la donnée de valeurs numériques + (par exemple, le changement d'unité peut être défini comme une + multiplication par un scalaire V=multiply(U,1000)=1000*U); +* L'opérateur est caractérisé par un domaine d'application qui + spécifie la portée de l'opération. Ce domaine comporte plusieurs + dimensions: + + - Un domaine temporel T qui spécifie les pas de temps sur lesquels + l'opération est appliquée; + - Un domaine spatial D qui spécifie la limite de portée de + l'opérateur et donc le domaine de définition du champ produit (qui + correspond dans ce cas à une restriction du domaine de définition + des champs en argument); + - Un domaine de composantes C qui spécifie les composantes sur + lesquelles l'opération est appliquée; + +.. note:: + Sur le plan informatique, l'opérateur aura également un paramètre + appelé *option* qui pourra indiquer par exemple dans une + opération unaire V=F(U) si le résultat V est une nouvelle instance + de champ ou la valeur modifiée du champ de départ U. Il pourra + également être amené à manoeuvrer des paramètres de type chaîne de + caractères, par exemple pour les opérations de changement de nom + des champs. + +De manière générale, on utilisera la notation +**(W|y)=OP[D,C,T](P,U,V,...)** pour désigner une opération OP: + +* **(V|y)**: V ou y désignent respectivement un résultat de type + champ ou de type valeur numérique ou logique; +* **[T,D,C]**: le domaine d'application de l'opérateur avec T le + domaine temporel, D le domaine spatial et C le domaine des + composantes; +* **P,U,V,...**: les paramètres numériques P (liste de valeurs + numériques) et les champs U,V,... en arguments de l'opérateur; + +On note également les particularités suivantes pour certaines +opérations: + +* Le domaine de définition du champ produit par une opération peut + être différent du domaine de définition des champs en argument. Par + exemple, dans le cas d'une opération de projection de champ, le + domaine spatial résultat peut être modifié par rapport au domaine de + définition initial, soit par la modification de la zone géométrique, + soit par modification des entités de maillage support. +* En dehors des opérations de type dérivée et intégrale, les valeurs + résultats sont déterminées de manière locale en chaque point du + domaine d'application. Par exemple, l'addition W=U+V consiste à + produire un champ W dont les valeurs en chaque point p sont la somme + des valeurs des composantes de U et V en ce point p: ``W=U+V <=> + W(:,p,:)=U(:,p,:)+V(:,p,:)`` pour tout point p du domaine + d'application D. + +Concept de domaine d'application +-------------------------------- + +Un domaine d'application est associé à une opération (et non pas à un +champ). Il a pour objectif de restreindre la portée de l'opération en +terme spatial, temporel, jeu des composantes. + +Pour ce qui concerne le domaine spatial D, plusieurs modalités de +définition sont envisagées: + +* la donnée d'un maillage ou d'un groupe d'éléments du maillage; +* un système de filtres qui peut combiner: + + - une zone géométrique définie indépendamment du maillage (boîte + limite par exemple), + - des critères conditionnant le calcul (par exemple U(t,p,c)=1 si + V(t,p,c)>> r=fa+fb + +* Effectuer les contrôles visuel et les diagnostics en ligne de + commandes python (cf. :ref:`Spécification des fonctions de + visualisation`):: + + >>> view(r) + +* Enregistrer les champs produits dans l'espace de travail sous forme + de fichier med. + +Sur cette base, on peut envisager une grande variété de cas d'utilisation: + +* La structure MED (champs, maillage et groupes de mailles) est + chargée dans le dataspace (l'étude SALOME techniquement) et peut + être explorée au niveau de l'arbre d'étude. L'arbre peut faire + apparaître: + + - les maillages et les groupes (qui peuvent être utilisés + éventuellement pour restreindre le domaine d'application) + - les champs dont on peut explorer les composantes et les itérations + +* On sélectionne plusieurs champs, éventuellement en sélectionnant les + pas de temps, les composantes et les domaines d'application spatiaux +* Menu contextuel --> Modifier un champ, Créer un champ, Prolonger un + champ, .... +* On choisi pour la suite "Créer un champ", une fenêtre de dialogue + s'affiche avec les saisies préremplies avec les données + sélectionnées. Il est possible de rajouter des éléments ou préciser + le domaine d'application +* Une partie de la boîte de dialogue est réservée à la saisie de la + ligne de commande python qui permet la création du nouveau champ. Le + nom dans l'étude pour le nouveau champ, ainsi que son nom python, + sont spécifié par l'utilisateur ({{H|un peu à la mode du module + system}}). +* L'opération est exécutée dans l'espace utilisateur (l'interface + python), de sorte que les variables soient projetées dans cet espace + et manipulables après l'opération au besoin. Par ailleurs, + l'utilisateur peut visualiser les ligne de commandes nécessaires à + taper pour exécuter sa requête. + +.. _specification_visualisation: + +Spécification des fonctions de visualisation +============================================ + +Dans le cadre du module MED, on appelle *fonction de visualisation* +une fonction qui permet d'avoir un aperçu graphique d'un champ, par +exemple au moyen d'une carte de champ construite sur une de ses +composante. Il s'agit là de vue de contrôle pour avoir une idée rapide +de la forme du champs. Pour créer des représentations spécifiques, on +préférera passer par les fonctions d'export vers le module PARAVIS. + +Les modules VISU et PARAVIS offre des interface de programmation C++ +et python qui permettent le pilotage depuis un module tiers comme le +module MED. On peut donc envisager une fonction de visualisation +intégrée au module de manipulation de champs, c'est-à-dire que l'on +déclenche sans sortir du module MED, et qui exploite les fonctions de +visualisation des modules VISU et/ou PARAVIS. + +Les captures d'écran ci-dessous illustrent la mise en oeuvre de la +fonction de visualisation: + +* Sélection d'un champ pour faire apparaitre le menu contextuel et + choisir l'option "Visualize": + +.. image:: images/xmed-gui-datasource-visualize_70pc.png + :align: center + +* Cette option déclenche l'affichage d'une carte de champ sur le cadre + d'affichage des viewers SALOME: + +.. image:: images/xmed-gui-datasource-visualize-result_70pc.png + :align: center + +Cette fonction est également disponible en ligne de commandes de +l'interface textuelle. Par exemple si ``f4`` désigne un champ de +l'espace de travail (importé des données source ou construit par les +opérations de champs), alors, on obtient une carte de champ par la +commande:: + + >>> view(f4) + +On peut remarquer d'ailleurs sur la capture d'écran de droite +ci-dessus que la demande de visualisation déclenche l'exécution de la +commande ``view`` dans la console de travail sur un champ identifié +par son numéro (3 dans l'exemple). + +.. note:: Tous les champs, qu'ils soient des champs chargés d'une + source de données ou construits par des opérations de champs sont + identifiés par un numéro unique et invariant tout au long de la + session de travail. + +Spécification des fonctions de persistance +========================================== + +On adopte le principe de fonctionnement suivant: + +* Le module n’assure pas la persistence au sens SALOME du terme, + c’est-à-dire qu’il ne permet pas la sauvegarde du travail dans une + étude au format hdf, ni le dump sous la forme de script python + SALOME. Le besoin n'est pas avéré et on peut même dire que ça n'a + pas de sens compte-tenu de l'usage envisagé pour le module MED. +* Par contre, le module fournit des fonctions de sauvegarde du travail + sous forme de fichiers med, l’export vers les modules VISU et + PARAVIZ, ou même la sauvegarde de l’historique de l’interface de + commandes. + +Ainsi donc, l'utilisateur aura une fonction (probablement graphique) +pour définir la sélection des champs de l'espace de travail à +sauvegarder. + +Spécification des fonctions d'export +==================================== + +.. warning:: EN TRAVAUX. + +Plusieurs export peuvent être proposés: + +* Export des champs vers le module PARAVIZ, dans l'objectif par + exemple d'en faire une analyse visuelle plus poussée qu'avec les + cartes de champs disponibles par défaut dans le module MED +* Export des données sous forme de tableau numpy, par exemple pour + permettre un travail algorithmique sur les valeurs des champs. + +Spécifications techniques +========================= + +Il s'agit d'exprimer ici les contraintes techniques applicables à la +conception et au développement du nouveau module MED. + +Implantation technique du module +-------------------------------- + +Il est convenu que le module MED existant dans la plate-forme SALOME +incarne le module de manipulation de champ. Dans la pratique, il +s'agit d'identifier clairement les parties à conserver, d'une part, +puis les parties à re-écrire, d'autre part. On peut partir sur les +hypothèses techniques suivantes: + +* Le noyau du module en charge des opérations de manipulation de + champs proprement dites est construit sur la base des paquets + logiciels MEDCoupling (lui-même basé sur le INTERP_KERNEL) et + MEDLoader. +* L'interface graphique du module MED est complétement re-écrite et + remplacée par une interface adaptée spécialement à la manipulation + des champs et la gestion des données associées +* Le contrôle visuel pourra être déclenché dans les visualisateurs + SALOME (servis par les modules VISU et/ou PARAVIZ); +* Le module n'assure pas la persistence au sens SALOME du terme, + c'est-à-dire qu'il ne permet pas la sauvegarde du travail dans une + étude au format hdf, ni le dump sous la forme de script python + SALOME. +* Par contre, il fournit des fonctions de sauvegarde du travail sous + forme de fichiers med, l'export vers les modules VISU et PARAVIZ, ou + même la sauvegarde de l'historique de l'interface de commandes. + +L'implantation technique des développements est représentée sur la +figure ci-dessous: + +.. image:: images/xmed-implantation.png + :align: center + +Le schéma représente les packages logiciels qui composent le module +MED (cf. |REF_CEA_VBE_MEDMEM|_): + +* La partie MEDMEM, représentées en blanc. Cette partie est conservée + pour compatibilité ascendante au niveau des applications métier qui + ont fait le choix historique de s'appuyer sur MEDMEM. Cette partie + du module MED aura tendance à disparaitre dans le futur au bénéfice + de MEDCoupling et MEDLoader. +* La partie MEDCoupling, représentée en orange et qui founrnit le + modèle MED mémoire de référence (composé de maillage et de champs) + et l'interface de programmation pour manipuler le modèle. Le paquet + MEDLoader est une extention dédiée à la persistence au format med + fichier (lecture et écriture de champs et de maillage dans des + fichiers med). +* La partie à développer pour la manipulation de champ, représentée en + bleu. + +.. note:: MEDCoupling peut être vu comme une structure de donnée + particulièrement adaptée à la manipulation des gros volumes de + données, en particulier par l'exploitation des possibilités de + parallélisation et la réduction de la tailles des structures de + données. En contrepartie, elle peut présenter un périmètre + fonctionnel moins large que MEDMEM. Pour cette raison, MEDMEM avait + été choisi comme socle de développement du prototype en 2010: + + * MEDCoupling ne permet pas de gérer des maillages composés de + plusieurs type de mailles et il est exclus de le faire évoluer + dans ce sens (c'est un choix fait pour les objectifs de + performances évoqués plus haut); + * MEDCoupling ne permet pas de gérer les supports qui expriment les + champs aux noeuds par élément ni aux points de gauss. Cette + seconde limitation a disparu en 2011. + + Aujourd'hui, on fait clairement le choix de MEDCoupling pour sa + qualité et sa robustesse, dans l'objectif d'une meilleure + maintenance à long terme. Par ailleurs, les différences + fonctionnelles avec MEDMEM, si elles existaient encore en 2012 pour + les besoins de la manipulation de champs, pourront être résorbées + dans un futur proche. + + diff --git a/src/MEDOP/doc/sphinx/medop-userguide.rst b/src/MEDOP/doc/sphinx/medop-userguide.rst new file mode 100644 index 000000000..bf00e8b1e --- /dev/null +++ b/src/MEDOP/doc/sphinx/medop-userguide.rst @@ -0,0 +1,748 @@ +.. meta:: + :keywords: maillage, champ, manipulation, guide utilisateur + :author: Guillaume Boulant + +.. include:: medop-definitions.rst + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Module MED: Guide d'utilisation de l'interface graphique +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Ce document est un guide rapide pour l'utilisation de l'interface +graphique du module MED. Il montre comment utiliser le module sur la +base de quelques exemples de référence, inspirés des cas d'utilisation +identifiés lors de l'analyse des besoins en matière de manipulation de +champs. + +.. warning:: Le document est autonome, mais il est vivement conseillé + de parcourir au préalable (ou en parallèle) :doc:`le document de + spécifications`, au moins pour fixer les + concepts et la terminologie. + +.. contents:: Sommaire + :local: + :backlinks: none + +Présentation générale du module MED +=================================== + +L'ergonomie générale d'utilisation du module de manipulation de champs +est inspirée des logiciels comme octave ou scilab. Elle associe une +interface graphique, pour sélectionner et préparer les données, avec +une interface texte (la console python) pour le travail effectif sur +les données. + +Pour cela, le module propose deux espaces utilisateurs qui sont +symbolisés par les rectangles rouges et vert sur la capture d'écran +ci-dessous: + +* **l'espace des données** (*dataspace*), dans lequel l'utilisateur + définit les sources de données med (*datasource*), c'est-à-dire les + fichiers med dans lesquels sont lus les champs et maillages. Cet + espace permet l'exploration des maillages et des champs fournis par + les différentes sources de données. +* **l'espace de travail** (*workspace*), dans lequel l'utilisateur + peut déposer des champs sélectionnées dans l'espace source, pour + ensuite les travailler par exemple pour produire des nouveaux champs + au moyen des fonctions de manipulation fournies par l'interface + textuelle (console python TUI). + +.. image:: images/xmed-gui-withframe.png + :align: center + +L'utilisation type des fonctions de manipulation de champs suit un +processus de la forme suivante: + +1. Chargement d'un fichier med dans l'espace de données (dataspace) et + exploration du contenu, composé de maillages et de champs définis + sur ces maillages et pouvant contenir un ou plusieurs pas de temps. +2. Sélection (graphique) des champs à manipuler dans l'espace de + travail (workspace), avec la possibilité de préciser des + restrictions d'utilisation (pas de temps, composantes, groupe de + maille). +3. Création de nouveaux champs par l'exécution d'opérations + algébriques (+,-,*,/) entre champs, l'application de fonctions + mathématiques standard (pow, sqrt, abs), ou encore l'initialisation + "from scratch" sur un maillage support. +4. Contrôle visuel rapide des champs produits (avec les modules VISU + et/ou PARAVIS de SALOME, pilotés automatiquement depuis l'interface + utilisateur) +5. Enregistrement d'une partie des champs produits dans un fichier med + + +Tour rapide des fonctions du module MED +======================================= + +Cette section présente des exemples d'utilisation du module XMED sous +la forme de "storyboard", et illustre au passage les fonctions mises à +disposition par le module. + +.. warning:: Cette section est en travaux. Tant que cet avis n'aura + pas disparu, veuillez en considérer le plan et le contenu encore + incomplets, temporaires et sujets à caution. + +Exemple 1: Explorer des sources de données +------------------------------------------ + +.. note:: Cet exemple présente les fonctions: + + * ajouter une source de données + * fonctions "Extends field series", "Visualize" + +.. |ICO_DATASOURCE_ADD| image:: images/ico_datasource_add.png + :height: 16px + +.. |ICO_XMED| image:: images/ico_xmed.png + :height: 16px + +.. |ICO_DATASOURCE_EXPAND| image:: images/ico_datasource_expandfield.png + :height: 16px + +.. |ICO_DATASOURCE_VIEW| image:: images/ico_datasource_view.png + :height: 16px + +Au démarrage, le module de manipulation de champs, identifié par +l'icône |ICO_XMED|, présente une interface vierge: + +.. image:: images/xmed-gui-start.png + :align: center + :width: 800px + +La première étape consiste à ajouter une ou plusieurs source de +données med dans le "dataspace". Pour cela, on clique sur l'icône "Add +datasource" |ICO_DATASOURCE_ADD| qui propose de sélectionner un +fichier med: + +.. image:: images/xmed-gui-datasource-selectfile.png + :align: center + :width: 800px + +L'opération ajoute une nouvelle entrée (datasource) dans l'espace de +données (dataspace). Le contenu peut être exploré en parcourant +l'arborescence. La figure ci-dessous (image de gauche) montre le +résultat du chargement du fichier ``timeseries.med`` contenant un +maillage de nom ``Grid_80x80`` sur lequel est défini un champ au noeud +de nom ``Pulse``. Par défaut, la composition du champs (en terme de +pas de temps et de composantes) n'est pas affichée pour éviter +l'encombrement visuel de l'arbre. On doit faire la demande explicite +au moyen de la commande "Expand field timeseries" +|ICO_DATASOURCE_EXPAND| disponible dans le menu contextuel associé aux +champs. Le résultat est affiché sur l'image centrale. La liste des +itérations du champ ``Pulse`` peut être consultée. + +.. |IMG_DATASOURCE_EXPLORE| image:: images/xmed-gui-datasource-explore-zoom.png + :height: 340px +.. |IMG_DATASOURCE_MENUCON| image:: images/xmed-gui-datasource-menucontextuel-zoom.png + :height: 340px +.. |IMG_DATASOURCE_EXPANDF| image:: images/xmed-gui-datasource-expand-zoom.png + :height: 340px + ++--------------------------+--------------------------+--------------------------+ +| |IMG_DATASOURCE_EXPLORE| | |IMG_DATASOURCE_MENUCON| | |IMG_DATASOURCE_EXPANDF| | ++--------------------------+--------------------------+--------------------------+ + +.. note:: En toute rigueur, le concept de *champ* dans le modèle MED + désigne une itération donnée. Un ensemble d'itérations est désigné + par le terme *série temporelle de champs*. Par abus de langage, et + s'il n'y a pas ambiguité, on utilisera le nom du champ pour + désigner à la fois le champs proprement dit ou la série temporelle + à laquelle il appartient. + +Enfin, il est possible au niveau du dataspace de visualiser la forme +générale du champ au moyen d'une carte scalaire affichée dans le +viewer de SALOME. Pour cela, on sélectionne le pas de temps à +visualiser et on utilise la commande "Visualize" |ICO_DATASOURCE_VIEW| +disponible dans le menu contextuel associé: + +.. image:: images/xmed-gui-datasource-visualize-zoom.png + :align: center + :width: 800px + +.. note:: Cette représentation graphique a pour objectif le contrôle + visuel rapide. Aussi, les fonctions du module VISU sont employées + par défaut, mais il est possible de faire l'affichage des cartes + scalaires au moyen du module PARAVIS (choix de préférence non + implémenté pour le moment, mais techniquement réalisable). + +Exemple 2: Rassembler des champs issus de différentes sources +------------------------------------------------------------- + +.. note:: Cet exemple présente les fonctions: + + * fonction "Use in workspace" + * fonction "Save" + +.. |ICO_DATASOURCE_USE| image:: images/ico_datasource_use.png + :height: 16px +.. |ICO_WORKSPACE_SAVE| image:: images/ico_workspace_save.png + :height: 16px + +L'objectif est de récupérer des données issues de différents fichiers +med, puis de les rassembler dans un même fichier en sortie. + +On commence par ajouter les sources de données med dans l'espace de +données (dataspace). Dans l'exemple ci-dessous, l'espace de données +contient deux sources de nom ``parametric_01.med`` et +``smallmesh_varfiled.med``. La première source contient le maillage +``Grid_80x80_01`` sur lequel est défini le champ ``StiffExp_01``. La +deuxième source contient le maillage ``My2DMesh`` sur lequel sont +définis deux champs de noms respectifs ``testfield1`` et +``testfield2``: + +.. image:: images/xmed-userguide-example2-datasource.png + :align: center + :width: 800px + +Pour l'exemple, on souhaite rassembler les champs ``StiffExp_01`` et +``testfield2`` dans un fichier de nom ``result.med``. La procédure +consiste à importer les deux champs dans l'espace de travail +(workspace), puis à sauvegarder l'espace de travail. Pour cela, on +sélectionne les champs et on utilise la commande "Use in workspace" +|ICO_DATASOURCE_USE| disponible dans le menu contextuel. Les deux +champs sélectionnés apparaissent dans l'arborescence de l'espace de +travail: + +.. image:: images/xmed-userguide-example2-workspace.png + :align: center + :width: 800px + +La sauvegarde de l'espace de travail est faite au moyen de la commande +"Save workspace" |ICO_WORKSPACE_SAVE| disponible dans la barre +d'outils du module. Une fenêtre de dialogue invite l'utilisateur à +spécifier le nom du fichier de sauvegarde: + +.. image:: images/xmed-userguide-example2-workspace-save.png + :align: center + :width: 800px + +Ce fichier ``result.med`` peut ensuite être rechargé dans le module +XMED (ou les modules VISU ou PARAVIS) pour vérifier la présence des +champs sauvegardés. + +.. BUG: plantage à l'utilsation dans XMED d'un fichier rechargé +.. (invalid mesh on field) + +.. _xmed.userguide.exemple3: + +Exemple 3: Appliquer une opération mathématique sur des champs +-------------------------------------------------------------- + +.. note:: Cet exemple présente les fonctions: + + * exécution d'opérations mathématiques dans la console TUI + * fonction "put" pour référencer un champ de travail dans la liste + des champs persistant. + * fonction "Visualize" depuis le TUI. + +L'usage le plus courant du module de manipulation de champs est +d'exécuter des opérations mathématiques dont les opérandes sont des +champs ou des composantes de ces champs. + +On se place dans une situation où les sources de données sont définies +dans le "dataspace" (dans l'exemple ci-après, une série temporelle de +nom ``Pulse``, contenant 10 pas de temps, définis sur un maillage de +nom ``Grid_80x80``, le tout issu du datasource ``timeseries.med``). + +Comme vu précedemment, pour manoeuvrer un champ dans l'espace de +travail, on sélectionne ce champ, puis on exécute la commande "Use in +workspace" |ICO_DATASOURCE_USE| du menu contextuel. Dans le cas +présent, un seul champ est sélectionné (contre deux dans l'exemple +précédent) et la commande ouvre alors une fenêtre de dialogue qui +permet de préciser les données sur lesquelles on souhaite +effectivement travailler et comment on veut les manoeuvrer: + +.. image:: images/xmed-gui-datasource-useinworkspace-alias.png + :align: center + :width: 800px + +.. note:: En l'état actuel du développement, l'interface propose + uniquement de définir le nom de la variable sous laquelle doit être + manoeuvré le champ dans la console de travail (TUI). Dans une + version ultérieure, il est prévue de pouvoir préciser la ou les + composante du champs à utiliser et un groupe de maille pour définir + une restriction géométrique. Inversement, il sera également + possible de choisir une série temporelle complète pour faire des + opérations globales sur l'ensemble des pas de temps. + +Aprés validation, le champ est placé dans l'arborescence du +"workspace" et une variable de nom ```` est créée +automatiquement dans la console de travail pour désigner le +champ. Dans cet exemple, ```` vaut ``f3``, positionné ainsi par +l'utilisateur pour rappeler que la variable correspond au pas de temps +n°3: + +.. image:: images/xmed-gui-workspace.png + :align: center + :width: 800px + +La manipulation peut commencer. Dans l'exemple ci-dessous, on crée le +champ ``r`` comme le résultat d'une transformation afine du champ +``f3`` (multiplication du champ par le facteur 2.7 auquel on ajoute +l'offset 5.2):: + + >>> r=2.7*f3+5.2 + +On peut poursuivre la manipulation du champs avec une variété +d'opérations qui sont détaillées dans les spécifications du module +(cf. :ref:`Spécification des opérations`): + + >>> r=f3/1000 # les valeurs de r sont celles du champ f3 réduites d'un facteur 1000 + >>> r=1/f3 # les valeurs de r sont les inverses des valeurs de f3 + >>> r=f3*f3 # les valeurs de r sont celles du champ f3 élevées au carré + >>> r=pow(f3,2) # même résultat + >>> r=abs(f3) # valeur absolue du champ f3 + >>> ... + +Les opérations peuvent utiliser plusieurs opérandes de type champs. Si +``f4`` désigne le pas de temps n°4 du champ ``Pulse``, alors on peut +calculer toute combinaison algébrique des deux champs:: + + >>> r=f3+f4 + >>> r=f3-f4 + >>> r=f3/f4 + >>> r=f3*f4 + +Avec au besoin l'utilisation de variables scalaires:: + + >>> r=4*f3-f4/1000 + >>> ... + +Dans ces exemples, la variable ``r`` désigne un champ de travail qui +contient le résultat de l'opération. Par défaut, ce champ de travail +n'est pas référencé dans l'arborescence du workspace. Si on souhaite +tout de même le référencer, par exemple pour qu'il soit pris en compte +dans la sauvegarde, alors on tape la commande:: + + >>> put(r) + +La fonction ``put`` a pour but de marquer le champ en argument comme +persistent, puis de le ranger dans l'arborescence du "workspace" afin +qu'il soit visible et sélectionnable. En effet, parmi tous les champs +qui pourront être créés dans la console pendant la session de travail, +tous n'ont pas besoin d'être sauvegardés. Certains sont même des +variables temporaires qui servent à la construction des champs +résultats finaux. C'est pourquoi, seuls les champs rangés dans +l'arborescence du workspace sont enregistrés lors de la demande de +sauvegarde du workspace. + +Les variables définies dans la console ont d'autres utilités. Tout +d'abord, elles permettent d'imprimer les informations concernant le +champ manoeuvré. Pour cela, on tape simplement le nom de la variable +puis retour:: + + >>> f3 + field name (id) = Pulse (3) + mesh name (id) = Grid_80x80 (0) + discretization = ON_NODES + (iter, order) = (3,-1) + data source = file:///home/gboulant/development/projets/salome/MEDOP/XMED/xmed/resources/datafiles/timeseries.med + +Elle peut également être utilisée comme argument des commandes de +gestion disponibles dans l'interface textuelle (dont la liste +détaillée est décrite à la section :ref:`Documentation de l'interface +textuelle`). Par exemple, la fonction ``view`` +permet d'afficher la carte scalaire du champ dans le viewer:: + + >>> view(f3) + +Donne: + +.. image:: images/xmed-gui-workspace-view.png + :align: center + :width: 800px + +.. note:: On remarquera ici qu'il est facile de comparer deux pas de + temps d'un champ, par exemple en calculant la différence ``f3-f4``, + puis en affichant un aperçu de la carte scalaire résultat au moyen + de la fonction ``view``:: + + >>> view(f3-f4) + +On peut enfin tout simplement afficher les données du champs par la +commande ``print``:: + + >>> print f3 + Data content : + Tuple #0 : -0.6 + Tuple #1 : -0.1 + Tuple #2 : 0.4 + Tuple #3 : -0.1 + Tuple #4 : 0.4 + ... + Tuple #6556 : 3.5 + Tuple #6557 : 3.3 + Tuple #6558 : 1.5 + Tuple #6559 : 0.3 + Tuple #6560 : 0.2 + +Il est important de noter que les opérations entre champs ne peuvent +être faites qu'entre champs définis sur le même maillage. Il s'agit là +d'une spécification du modèle MED qui interdit d'envisager les +opérations entre champs définis sur des maillages géométriquement +différents. Techniquement, cela se traduit par l'obligation pour les +objets informatique *champs* de partager le même objet informatique +*maillage*. + +Dans l'hypothèse où on souhaite utiliser des champs définis sur des +maillages différents, par exemple pour manoeuvrer les valeurs des +champs à l'interface de deux maillages partageant une zone géométrique +2D, il faut d'abord ramener tous les champs sur le même maillage de +surface par une opération de projection. + +.. note:: Même si ceci est techniquement possible avec la bibliothèque + MEDCoupling, cet type d'opération de projection n'est pas encore + disponible dans le module de manipulation de champs (prévu en + 2012). + +Un autre besoin plus classique est l'utilisation de champs définis sur +des maillages géométriquement identiques, mais techniquement +différents, par exemple lorsqu'ils sont chargés de fichiers med +différents. Pour traiter ce cas de figure, la bibliothèque MEDCoupling +prévoit une fonction de "Changement du maillage support", dont +l'utilisation au niveau du module de manipulation de champs est +illustrée dans :ref:`l'exemple 4` ci-après. + +.. _xmed.userguide.exemple4: + +Exemple 4: Comparer des champs issues de différentes sources +------------------------------------------------------------ + +.. note:: Cet exemple présente les fonctions: + + * Changement du maillage support "change underlying mesh" + +On se place ici dans le cas de figure où des champs ont été produits +sur le même maillage, au sens géométrique, mais enregistrés dans des +fichiers med différents. C'est le cas par exemple d'une étude +paramétrique où plusieurs calculs sont effectués avec des variantes +sur certains paramètres du modèle simulé, chaque calcul produisant un +fichier med. + +Soit ``parametric_01.med`` et ``parametric_02.med`` deux fichiers med +contenant les champs que l'on souhaite comparer, par exemple en +calculant la différence des valeurs et en visualisant le résultat. + +Aprés le chargement des sources de données dans le module XMED, +l'utilisateur se trouve en présence de deux maillages, au sens +technique du terme cette fois-ci, c'est-à-dire que les champs sont +associées à des objets informatiques maillage différents, bien que +géométriquement identiques. + +Or, les fonctions de manipulation de champs ne permettent pas les +opérations sur des champs dont les maillages supports sont différents +(voir la remarque à la fin de :ref:`l'exemple +3`). + +Pour résoudre ce cas de figure, le module de manipulation de champs +met à disposition la fonction "Change underlying mesh" qui permet de +remplacer le maillage support d'un champ par un autre à partir du +moment où les deux maillages sont géométriquement identiques, +c'est-à-dire que les noeuds ont les mêmes coordonnées spatiales. + +.. |ICO_DATASOURCE_CHG| image:: images/ico_datasource_changeUnderlyingMesh.png + :height: 16px + +Dans l'exemple proposé, l'utilisateur sélectionne le premier pas de +temps du champ ``StiffExp_01`` du "datasource" ``parametric_01.med``, +puis l'importe dans l'espace de travail au moyen de la commande "Use +in workspace" |ICO_DATASOURCE_USE|. Il sélectionne ensuite le premier +pas de temps du champs ``StiffExp_02`` du "datasource" +``parametric_02.med``, mais l'importe dans l'espace de travail au +moyen de la commande "Change underlying mesh" |ICO_DATASOURCE_CHG|. La +fenêtre de dialogue ci-dessous s'affiche et invite l'utilisateur à +choisir le nouveau maillage support par sélection dans l'arborescence +du "dataspace": + +.. image:: images/xmed-gui-datasource-changeUnderlyingMesh.png + :align: center + +Dans cet exemple, on sélectionne le maillage ``Grid_80x80_01`` support +du champ ``StiffExp_01``, avec lequel on souhaite faire la +comparaison. Après validation, l'arborescence du workspace contient le +champ ``StiffExp_02`` défini sur le maillage ``Grid_80x80_01``: + +.. image:: images/xmed-gui-datasource-changeUnderlyingMesh_wsview.png + :align: center + +.. note:: La fonction "Change underlying mesh" ne modifie pas le champ + sélectionné dans le "dataspace" (principe de base de fonctionnement + du dataspace), mais crée une copie du champ dans l'espace de travail + pour ensuite remplacer le maillage support. D'où le nom par défaut + pour le champ ``dup()`` (dup pour + "duplicate"). + +Il reste à associer une variable à ce champ pour le manipuler dans la +console. Ceci peut être fait au moyen de la commande "Use in console", +disponible dans le menu contextuel du workspace. + +En définitif, si ``f1`` désigne le champ issu du datasource +``parametric_01.med`` et ``f2`` le champ issu du datasource +``parametric_02.med`` par la procédure décrite ci-dessus, alors la +comparaison des deux grandeurs peut être faite comme pour le cas de +:ref:`l'exemple 3`:: + + >>> r=f1-f2 + >>> view(r) + +.. note:: En remarque générale sur cet exemple, il convient de noter + les points suivants: + + * l'égalité géométrique de deux maillages est établie à une marge + d'erreur prés qu'il est possible de définir techniquement, mais + qui n'est pas ajustable au niveau de l'interface du module de + manipulation de champs. Elle est fixée à une valeur standard qui + permet de traiter la plupart des cas utilisateur. On verra à + l'usage s'il est nécessaire de remonter ce paramètre au niveau de + l'interface. + * L'utilisateur doit faire la démande explicite de changer le + maillage support d'un champ, en prévision de la comparaison de + champs issus de datasource différentes. Il s'agit là d'un choix + fonctionnel délibéré pour que l'utilisateur garde trace des + modifications faites sur les données (pas de modification + automatiques à l'insu de l'utilisateur, même sous prétexte + d'amélioration de l'ergonomie). + + +Exemple 5: Créer un champ sur un domaine spatial +------------------------------------------------ + +.. note:: Cet exemple présente les fonctions: + + * initialisation par une fonction de la position spatiale + * initialisation sur un groupe de maille + +Le domaine géométrique de définition du champs à créer est spécifié +ici par la donnée d'un groupe de mailles. Ce cas d'usage est +typiquement prévu pour produire les conditions de chargement initial +d'une structure, par exemple en définissant un champ sur une surface +de la géométrie, identifiée par un nom de groupe de mailles. + +.. warning:: DEVELOPPEMENT EN COURS + +Exemple 6: Extraire une partie d'un champ +----------------------------------------- + +.. note:: Cet exemple présente les fonctions: + + * extraire une composante (ou un sous-ensemble des composantes) + * extraire un domaine géométrique (valeurs sur un groupe de maille) + * extraire un ou plusieurs pas de temps. + +.. warning:: DEVELOPPEMENT EN COURS + + On doit illustrer ici les fonctions de restriction, qui + permettraient de récupérer certaines composantes uniquement. Le + principe est qu'on crée un nouveau champ qui est une restriction du + champ argument à une liste de composantes à spécifier (utiliser la + fonction __call__ des fieldproxy). + +Pour l'extraction des pas de temps, on peut se ramener au cas de +l'exemple 2 avec une seule source de donnée. + +Exemple 7: Créer un champ à partir d'une image to[mp]ographique +--------------------------------------------------------------- + +.. note:: Cet exemple présente les fonctions: + + * Création d'un champ sans datasource (ni maillage, ni champs), à + partir d'un fichier image + +En tomographie ou en topographie, les appareils de mesure produisent +des images qui représentent une grandeur physique en niveaux de gris +sur un plan de coupe donné. L'image ci-dessous représente par exemple +une vue interne du corps humain faite par IRM: + +.. image:: images/xmed-irm.png + :align: center + :width: 600px + +Cette image est un ensemble de pixels organisés sur une grille +cartesienne. Elle peut donc être modélisée sous la forme d'un champ +scalaire dont les valeurs sont définies aux cellules d'un maillage +réglés de même taille que l'image (en nombre de pixels): + +.. image:: images/xmed-irm-field.png + :align: center + :width: 600px + +Le module de manipulation de champ fournit un utilitaire appelé +``image2med.py`` qui permet d'appliquer ce principe à la conversion +d'un fichier image en fichier med contenant la représentation de +l'image sous forme d'un champ scalaire (seul le niveau de gris est +conservé):: + + $ /bin/salome/xmed/image2med.py -i myimage.png -m myfield.med + +.. |ICO_IMAGESOURCE| image:: images/ico_imagesource.png + :height: 16px + +Cette opération de conversion peut être faite automatiquement dans +l'interface graphique du module au moyen de la commande "Add Image +Source" |ICO_IMAGESOURCE| disponible dans la barre d'outils. Cette +commande ouvre la fenêtre suivante pour inviter l'utilisateur à +choisir un fichier image: + +.. image:: images/medop_image2med_dialog.png + :align: center + +Le nom du fichier med résultat est proposé par défaut (changement de +l'extention en ``*.med``) mais il peut être modifié. Enfin, on peut +demander le chargement automatique du fichier med produit pour ajout +dans l'espace de donnée. Les champs peuvent alors être manipulés comme +dans les cas d'utilisation standard. + +Par exemple, l'image ci-dessous affiche le résultat de la différence +entre deux images, ajoutée à l'image de référence: si i1 et i2 +désignent les champs créés à partir des deux images, on représente ``r += i1 + 5*(i2-i1)`` où le facteur 5 est arbitraire et sert à amplifier +la zone d'intérêt (en haut de l'oeil gauche): + +.. image:: images/xmed-irm-diff.png + :align: center + :width: 600px + +L'exemple ci-dessous est le résultat du chargement d'une image +tomographique issue du projet MAP (Charles Toulemonde, +EDF/R&D/MMC). L'image tomographique: + +.. image:: images/champ_altitude_MAP.png + :align: center + :width: 600px + +Le résultat du chargement: + +.. image:: images/medop_image2med_tomographie.png + :align: center + :width: 800px + +Exemple 8: Continuer l'analyse dans PARAVIS +------------------------------------------- + +.. note:: Cet exemple présente les fonctions: + + * Export de champs vers le module PARAVIS. + +Les possibilités de représentation graphique des champs fournies par +le module MED ont pour seul objectif le contrôle visuel rapide. Par +défaut, le viewer de VISU est employé. + +Pour une analyse plus détaillées des champs, il est nécessaire de +poursuivre le travail dans PARAVIS. Le module de manipulation de +champs offre une fonction qui simplifie ce passage, en faisant le +chargement automatique dans PARAVIS et en proposant une visualisation +par défaut (carte de champs scalaire). + +Pour cela, il faut sélectionner dans l'espace de travail les champs à +exporter, puis déclencher la fonction d'export depuis le menu +contextuel associé: + +.. image:: images/medop_exportparavis.png + :align: center + +Les champs sélectionnés sont regroupés dans une entrée MED du +navigateur PARAVIS, et le premier champ est affiché sous forme de +carte de champ: + +.. image:: images/medop_exportparavis_result.png + :align: center + :width: 800px + +.. note:: La fonction d'export est une fonction de confort. La même + opération peut être faite manuellement en procédant d'abord à + l'enregistrement des champs sous forme de fichier MED, puis en + chargeant le fichier généré dans le module PARAVIS pour + visualisation. + +.. _xmed.userguide.tui: + +Utilisation de l'interface textuelle du moduel MED (TUI) +======================================================== + +Toutes les opérations menées au moyen de l'interface graphique peuvent +être réalisées (avec plus ou moins de facilité) avec l'interface +textuelle. Le module de manipulation de champs peut même être utilisé +exclusivement en mode texte. Pour cela, on lance la commande:: + + $ /medop.sh + +Cette commande ouvre une console de commandes ``medop>``. Un fichier +med peut être chargé et travaillé, par exemple pour créer des champs à +partir des données du fichier. + +Que l'on soit en mode texte pur ou en mode graphique, un séquence de +travail type dans la console peut ressembler au jeu d'instructions +suivantes:: + + >>> load("/path/to/mydata.med") + >>> la + id=0 name = testfield1 + id=1 name = testfield2 + >>> f1=get(0) + >>> f2=get(1) + >>> ls + f1 (id=0, name=testfield1) + f2 (id=1, name=testfield2) + >>> r=f1+f2 + >>> ls + f1 (id=0, name=testfield1) + f2 (id=1, name=testfield2) + r (id=2, name=testfield1+testfield2) + >>> r.update(name="toto") + >>> ls + f1 (id=0, name=testfield1) + f2 (id=1, name=testfield2) + r (id=2, name=toto) + >>> put(r) + >>> save("result.med") + +Les commandes principales sont: + +* ``load``: charge un fichier med dans la base de données (utile + uniquement en mode texte pur):: + + >>> load("/path/to/datafile.med") + +* ``la``: affiche la liste de tous les champs chargés en base de données ("list all") +* ``get``: définit un champ dans l'espace de travail à partir de son + identifiant (utile plutôt en mode texte pur car l'interface + graphique permet de faire cette opération par sélection d'un champ + dans le dataspace):: + + >>> f=get(fieldId) + +* ``ls``: affiche la liste des champs présent dans l'espace de travail ("list") +* ``put``: met un champ en référence dans l'*espace de gestion*:: + + >>> put(f) + +* ``save``: sauvegarde tous les champs référencés dans l'espace de + gestion dans un fichier med:: + + >>> save("/path/to/resultfile.med") + +.. note:: On peut faire à ce stade plusieurs remarques: + + * la commande ``load`` charge uniquement les méta-informations + décrivant les maillage et les champs (noms, type de + discrétisation, liste des pas de temps). Les maillages et les + valeurs physiques des champs sont chargées ultérieurement (et + automatiquement) dés lors qu'elles sont requises par une + opération. Dans tous les cas, les données med (méta-informations + et valeurs) sont physiquement stockées au niveau de l'espace + *base de données*. + * la commande ``get`` définit en réalité un *manipulateur de champ* + dans l'espace de travail, c'est-à-dire une variable qui fait la + liaison avec le champ physique hébergé dans la base de + données. Les données physiques ne circulent jamais entre les + espaces, mais restent centralisées au niveau de la base de + données. + +Les commandes TUI suivantes nécessitent de travailler dans +l'environnement graphique: + +* ``visu``: afficher une carte de champ pour contrôle visuel rapide + (pas de paramettrage possible) + + >>> view(f) + + diff --git a/src/MEDOP/doc/sphinx/medop-workingnotes-2010.rst b/src/MEDOP/doc/sphinx/medop-workingnotes-2010.rst new file mode 100644 index 000000000..724c9a832 --- /dev/null +++ b/src/MEDOP/doc/sphinx/medop-workingnotes-2010.rst @@ -0,0 +1,461 @@ +.. meta:: + :keywords: maillage, champ, manipulation + :author: Guillaume Boulant + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +ANNEXE: Note de travail concernant le chantier XMED 2010 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +.. contents:: Sommaire + :local: + :backlinks: none + +Principes directeurs du développement +===================================== + +En matière de développement: + +* On ne cherche pas d'emblée à s'inscrire dans la fabrication d'un + module SALOME diffusable dans la version d'exploitation 2010 (SALOME + 6). La raison est double: (i) on souhaite au moins pour 2010 ne pas + devoir tenir compte des contraintes de temps SALOME et (ii) le + produit envisagé fin 2010 est une maquette qui cherche à éprouver + l'ergonomie générale d'utilisation et en aucun cas on ne peut + garantir la réalisation d'un module SALOME compatible avec les + exigences de mise en exploitation. +* On ne cherche pas d'emblée à capturer tous les cas d'application, + mais à concevoir un développement qui acceptera les extensions de + périmètres dans des conditions raisonnables. Aussi, les + fonctionnalités développées seront celles qui sont nécessaires à la + réalisation des cas d'application de référence; + +En matière d'ergonomie: + +* L'interface utilisateur de référence (appelé espace de travail dans + le volet de spécifications fonctionnelles) est l'interpréteur + python. Les fonctionnalités doivent être pensées pour un usage + adapté à une interface textuelle (TUI) de ce type. +* La création d'une interface graphique (GUI) peut être envisagée en + complément et comme un moyen de manipuler graphiquement les + fonctionnalités développées pour l'interface textuelle et pour aider + la préparation des variables dans l'interface python. +* Le modèle d'un processus de manipulation de champs est: + + - Préparation du jeu de variables U, V, ... représentant les champs + à manipuler. C'est à ce stade que l'on résoud la question de + sélection des données (dans un champ publié dans l'arbre d'étude, + par un module de calcul ou par chargement d'un fichier med) + - Utilisation des variables avec une sémantique la plus proche + possible du modèle conceptuel et des spécifications + fonctionnelles; + - Création des variables qui représentent les résultats des + fonctions de manipulation; + - Persistence (fichier med), visualisation (SALOME) ou export (vers + une structure qui peut être directement utilisable en numpy) + +Sur le plan technique: + +* On souhaite spécifier clairement le conteneur SALOME des fonctions + de manipulation de champs. Pour discussion: + + - Il apparaît que les modules SALOME MED et VISU contiennent déjà + des fonctions qui peuvent faire partie des fonctions de + manipulations de champs (en particulier pour l'exploration des + structures MED, leur visualisation et la sélection des données à + manipuler). + - Dans la mesure où le module MED n'est pas utilisé à ce jour (en + tout cas pas sous sa forme de module SALOME) et compte-tenu du + caractère obsolescent du module VISU (amené à être remplacé sur le + plan fonctionnel par le module PARAVIS), on pourrait examiner la + création d'un module dédié à la manipulation des maillages et des + champs par l'agrégation technique au sein d'un même module des + fonctions des modules MED et VISU. + +Au moins dans un premier temps, on se donne les limites suivantes: + +* Une opération ne peut pas combiner des pas de temps différents. Dans + l'hypothèse où cette limite venait à être levée, on doit spécifier + le pas de temps de la donnée résultat; +* Le domaine d'application d'une opération pourra être défini + exclusivement par la donnée d'un maillage ou un groupe d'éléments du + maillage; +* On ne traite pas le cas des champs qui prennent leurs valeurs aux + points de gauss ou aux noeuds par élément. Une particularité de ces + types de support est que le repérage de la position implique deux + indices (par exemple l'indice de la maille, puis l'indice du point + de gauss). + +Eléments de conception +====================== + +Plan général +------------ + +On peut par exemple imaginer une maquette du genre: + +* En C++ dans MEDGUI, charger un fichier med et donner une vue de la + structure des maillages et des champs dans l'arbre d'étude. +* Sélectionner un élément (par exemple un pas de temps d'un champ) et + le menu contextuel permet d'exporter ce champ dans la console python + pour manipulation. Pour cela, s'inspirer de la fonction + ``XCADGUI::OnLoadScript()`` du XCADGUI pour manoeuvrer un objet + PythonConsole. +* L'élément est marqué comme ayant été exporté, on peut imaginer une + récupération ultérieure. +* Exporter un deuxième champ cohérent avec le premier (même pas de + temps et défini sur le même maillage avec le même support, on + s'arrange pour). +* Dans la console python, faire les opérations sur les champs +* Publication du champ résultat dans l'arbre d'étude pour sauvegarde + ultérieure. C'est a priori le gros morceau qui consiste à faire un + objet CORBA MED à partir d'un objet MED standard, en plus défini + dans la console python (sous forme d'objet python). + +Quand ce premier cas d'utilisation est au point, on peut envisager de +le compléter par les opérations suivantes + +* exporter le résultat med dans un fichier +* visualiser les champs produits + +Plan de développement: + +* Faire une maquette en MEDMEM pur d'abord, car quelque soit le choix + d'architecture, l'opération physique se déroulera en définitif au + niveau de MEDMEM pur. +* Prévoir une implémentation des opérations sous forme de fonctions + informatiques, même les opérations algébriques (+,-,*,/). Pour ces + dernières et dans certaines conditions (quand on manipule + directement les strutures MEDMEM et non pas les objets CORBA), + l'utilisation des formes A+B, A-B, ... peuvent être rendues + possibles. Dans ce cas, voir la possibilité de combiner plusieurs + opérations algébriques sur une seule ligne: A+B-C*0.3. +* On peut charger la structure MED sous forme d'objet CORBA publiable + dans l'étude, de sorte d'avoir accés aux méta-données et pouvoir par + exemple sélectionner les champs d'intérêt. De cet objet CORBA, on ne + récupère que les informations nécessaires au chargement d'un champs: + le nom du champs, le nom de son maillage associé, les identifiants + du pas de temps, au besoin une structure Field non chargée (par + exemple pour récupérer plus facilement le maillage). +* Un mécanisme (à développer à partir du PyConsole par exemple) + pourrait alors permettre le chargement des champs sélectionnés dans + la console python et sous un nom facile à manoeuvrer. Prendre + inspiration sur XCADGUI::LoadIntoPythonConsole(). +* A priori, les données sont physiquement chargée dans le GUI. Au + besoin, il semble possible (cf. MED_i::init) de fabriquer une objet + CORBA field à partir d'un field standard (à tester). + +Une autre idée est de récupérer le pointeur CORBA MED dans la console +python et de tirer les données à partir de là. Ajouter une couche de +wrapping python pur pour gérer les cas de simplification (surcharge +des opérations arithmétiques par exemple). + +Besoins complémentaires: + +* L'interpréteur doit contenir des éléments d'aide (par exemple un + help qui liste les opérations possibles sur les champs chargés) +* prévoir quelques fonctions de visu et de persistence. Cela commence + probablement par des fonctions de publication dans l'étude des + champs créés par les opérations de manipulation. Les champs sont + physiquement ajouté automatiquement à la structure med par le MedOp + mais il n'est pas obligatoirement publié => fournir un moyen de + publication. + +Limitations actuelles (liées à la conception de MEDMEM): + +* les champs doivent être gérés par la même structure MED car ils + doivent partager le même support. +* les opérations possibles dans MEDMEM sont entre champs pris sur un + pas de temps (Q: les pas de temps peuvent-ils être différents). + + +Développements +-------------- + +Développement de classes proxy: + +* FieldProxy, FieldTimeSeriesProxy +* Attention pour les éries temporelles, le SUPPORT med peut être + différent en chaque pas de temps (par exemple en cas d'extension + spatiale du champ au cours du temps). + +MEDMEM_MedDataManager: + +* FIX: test de l'implémentation C++ au travers de la fonction test() du + MedOperator ==> OK. Quand on fait la même opération depuis python + via l'interface SWIG ==> au deuxième appel de getFieldDouble, le + destructeur du champ semble être appelé. Pb de gestion des pointeurs? + + +Evolutions à prévoir +==================== + +Concernant MEDMEM: + +* FIX: SALOME_MED::MED::getField devrait pouvoir être appelée + plusieurs fois de suite puisqu'on recycle la référence si elle est + déjà chargée. +* IMP: MEDMEM::MED faire une gestion des chargements des champs (par + exemple avec un getField qui renvoie le champ s'il est déjà chargé + ou le charge et le renvoie sinon). +* IMP: Récupérer le nom du fichier med à partir de l'objet MED, en + passant a priori par le driver associé. Plusieurs driver peuvent + être associés à une structure MED car les données peuvent être + chargées en plusieurs fois et de plusieurs fichiers. Il faut donc + étendre la structure MED pour avoir accés à la liste des driver puis + de cette liste déduire les noms des fichiers. +* IMP: Opérations combinant des champs sur des support différents ne + peuvent pas être faites par l'API (une exception est levée en cas de + supports incompatibles), mais on peut imaginer le faire en + manoeuvrant les tableaux de données directement. +* INF: faire le point sur les fonctions utilitaires autour de MEDMEM + et de son interface SWIG (ex: dumpMEDMEM.py, med_opfield_test.py). +* IMP: dans MEDMEM::MED et SALOME_MED::MED, pouvoir enlever un champ + préalablement ajouté: une fonction removeField en complément de + addField. + +Concernant l'interface SALOME_MED: + +* IMP: Fonctions algébriques, qui seront implémentées au niveau de la + structure MED et requêtées au niveau des classes proxy en spécifiant + les identifiants des champs impliqués et les paramétres requis (pas + de temps en particulier). + +Concernant le module MED: + +* IMP: pourvoir exporter la structure med dans un fichier med (la + structure ayant pu être enrichie par la publication de champs créés + par les operations de champs. + + +Historique des travaux +====================== + +20100726 : mise au point du schéma de conception +------------------------------------------------ + +Choix entre MEDMEM et MEDCoupling: on reste sur MEDMEM pour plusieurs +raisons: + +* MED Coupling ne peut pas gérer des mailles de dimensions différentes + dans un même modèle (choix faits dans un soucis de performance dans + l'accès à une structure de donnée compact). On peut contourner le + problème en définissant deux champs pour traiter chacun des type de + mailles. +* Un champ repose sur un maillage complet (pas de notion de profil, + mais cela peut être émulé en créant deux maillages) +* Le concept de point de gauss n'existe pas (pas implémenté) + +TODO: + +* Idéalement, il conviendrait de faire un état des lieux du module + MED, en particulier des éléments MEDMEM (le coeur), les interfaces + CORBA associées (MED.idl implémenté dans le package source + MEDMEM_I), l'engine (composant SALOME d'interface MED_Gen.idl et + implémenté dans le package source MED) et le GUI (MedGUI.cxx + implémenté dans le package source MEDGUI). + +* Ergonomie TUI et modèle CORBA associé: + + 1. Charger un objet medmem (puis les objets métier mesh et field) + sur un domaine d'application donné. + 2. En faire des variables disponibles dans l'interface TUI et que + l'on peut manipuler dans des opérations algébriques. + 3. Pouvoir au besoin en faire des objets CORBA pour l'interface avec + les autres modules SALOME. + +* Compléter le diagramme de la structure informatique de MED (en + particulier l'implémentation des interface IDL). +* Préparer un module de travail XMED (organisation d'une bibliothèque) + +Tests à réaliser: + +* Est-il possible de faire des opérations algébriques à partir des + objets SALOMEMED (objects CORBA MED)? +* Création d'un objet MED_i à partir d'une objet MED pur préalablement + chargé en mémoire. + +A retenir: + +* Des opérations de champs sont possibles sur des champs à des pas de + temps fixés. Si l'opération doit être menée sur plusieurs pas de + temps, alors itérer sur chaque pas de temps. L'idée ici est + d'introduire le concept de série temporelle de champs en temps + qu'objet manipulable. +* Pour deux champs différents de la même structure MED, la données des + identifiants dt et it ne correspond pas forcément au même instant + absolu (en tout cas rien ne le garanti, même si c'est tout de même + une pratique courante). + +20101005 : première maquette de démonstration de l'ergonomie en MEDMEM pur +-------------------------------------------------------------------------- + +XMED: svn révision 16 +Travailler avec le fichier de donnée testfield.med joint. + + +20101007 : Vers une maquette CORBA +---------------------------------- + +Le contexte d'utilisation des opérations de champs est l'environnement +SALOME. Le support de gestion des données est donc l'étude SALOME. Au +plus bas niveau, les champs sont des objets MEDMEM instanciés dans une +session SALOME (soit par un code de calcul intégré, soit par +chargement des données à partir d'un fichier med). Ces objets sont en +général référencés dans l'étude SALOME sous la forme d'objets CORBA de +classe SALOMEMED::FIELD. Plus exactement, l'étude SALOME gère des +SObject (Study Object) dont un attribut est une référence vers un +objet CORBA de classe SALOMEMED::FIELD qui lui-même encapsule un objet +MEDMEM::Field. + +On peut donc envisager une solution dans laquelle on donne à +l'utilisateur des poignées de manipulation des objets +SALOMEMED::FIELD, par exemple au moyen d'un modèle informatique de +type proxy. Cela signifie que l'utilisateur ne manipule pas +directement des objets MEDMEM mais des objets python qui font +l'interface (à concevoir et implémenter, a priori avec un design +pattern de type proxy). + +L'utilisation directe des objets MEDMEM aurait pu être une solution +extremement pratique dans la mesure où ces objets en l'état peuvent +être combinés dans des opérations de champs (c'est déjà +implémenté). Par contre, ce procédé souffre de limitations importantes +dans la gestion et la circulation des données pour les différents cas +d'utilisation envisagés (visualisation, export, transfert à un autre +module SALOME). + +L'avantage de la solution proposée est multiple: + +* Elle permet de travailler sur une structure MED cohérente pour + intégrer les résultats des opérations de calculs et combiner des + champs cohérents entre eux. Tout passe par des classes proxy qui + pourront s'assurer de la cohérence des opérations demandées et + exécuter automatiquement les fonctions de pré-traitement ou + post-traitement requises pour ces opérations. On peut imaginer par + exemple que les requêtes d'opération soient envoyées par les classes + proxy à la structure MED à laquelle les champs sont associés pour + piloter l'opération en MEDMEM pur. +* Elle permet d'automatiser un certain nombre d'opérations + implicites. Par exemple si deux champs ne sont pas définis dans la + même unité, un changement d'unité peut être effectué automatiquement + par la classe proxy avant de commander l'opération au niveau + MEDMEM. +* Elle permet de laisser les données sur le container SALOME et de + réaliser des opérations sans rappatrier les données en local (qui + peuvent être en trés grand nombre). +* Elle permet d'étendre facilement l'ergonomie de manipulation des + champs, par exemple en définissant la notion de *série temporelle de + champs*, ou encore les concepts de *domaine de définition* évoqués + dans les spécifications fonctionnelles. +* Elle rend immédiat la circulation des données entre modules SALOME, + puisque les champs restent accessble par des objets CORBA, en + particulier pour la visualisation ou l'export des champs produits + par les opérations. + +Elle a cependant des inconvénients et/ou limitations: + +* Elle nécessite l'implémentation d'une classe proxy pour encapsuler tous + les appels aux objets SALOME_MED (et donc MEDMEM). Cette interface + se limite a priori aux opérations de champs (les opérations + algébriques dans un premier temps). +* Les champs à manipuler dans une opération donnée doivent être gérés + par la même structure MED. + +Il est à noter également que les interfaces de programmation de +SALOMEMED (interface CORBA pour MEDMEM) devront être étendues pour +permettre des requêtes de manipulations de champs (fonctions addition, +soustraction, multiplication, ...). Pas de contrainte ici sur +l'ergonomie puisque la manipulation par l'utilisateur se fera au +niveau des classes proxy uniquement. + + +Hypothèses: + +* On tente ici une maquette qui exploite dans la mesure du possible le + fonctionnement actuel du module MED, en particulier la gestion des + données dans l'étude. +* Dans une deuxième version, on pourra examiner sérieusement la + révision de la gestion des données dans le module, quitte à la + spécifier et maquetter dans XMED pour intégration ultérieure dans + MED. Exemple: + + - Pouvoir gérer plusieurs structures med dans l'étude. + +* Enfin, on exploite MEDMEM en l'état. Pour les besoins de la gestion + des données (gestion des chargements des champs en particulier, + références croisées pour retrouver le med à partir du champ par + exemple, ...), il pourra être nécessaire de faire évoluer MEDMEM. Il + faut pouvoir par ailleurs gérer indifféremment une structure med (et + les champs qui y sont associés) qu'elle soit créée en mémoire from + scratch ou chargée d'un fichier (donc attention avec les opérations + de lecture read(), sur les maillages comme sur les champs). La + structure med permet d'obtenir les méta données (meta-field par + exemple) mais ne permet pas de savoir si les données sont + physiquement chargées ou pas. + + +Révisions: + +* XMED svn revision 21 + tarball MED_SRC-20101014-15h26m.tgz. + Première version qui permet d'importer un champ dans la console + python sous la forme d'un FieldProxy. Ne permet pas encore de faire + des opérations. Introduction dans le module MED de l'interface MEDOP + pour prendre en charge les opérations sur les champs. + + +20101019 : Maquette de démonstration pour l'addition +---------------------------------------------------- + +Cette maquette implémente une solution technique de bout en bout (de +l'interface python aux objets MEDMEM, en passant par le fieldproxy +puis les servants CORBA pour les operations, ...) mais sur le +périmètre de l'addition de champs sur tout leur domaine de définition +et pour un pas de temps donné. + +Limitations: + +* gére l'addition de champs de type double uniquement (parceque le + reste n'est pas implémenté) + +Révisions: + +* XMED: svn révision 25 +* MED: cvs tag BR_medop_20101019 + + +20101020: Fonctions complémentaires +----------------------------------- + +Cette version test la faisabilité des fonctions complémentaires pour +accompagner la manipulation de champs. Cela comprend en particulier: + +* **la sauvegarde des champs produits** dans un fichier med (un champ ou + toute la structure med). Pour cela, on définit un med proxy comme + l'extention du SALOME_MED::MED (prévir plutôt d'implémenter ce type + de fonction au niveau C++ pour permettre un usage au niveau du GUI + C++?). +* **la visualisation d'un champ** au moyen du module VISU. +* **des fonctions d'aide interactives** pour assister l'utilisateur + dans la console de manipulation des champs. + + +Questions: + +* peut-on sauvegarder un champ unique? +* peut-on faire en sorte que ce soit l'affectation à une variable qui + provoque l'ajout du champ à la structure med (ou plus exactement qui + supprime tous les champs intermédiaires). + + +Révision: + +* XMED: svn revision 31 +* MED: cvs tag BR_medop_20101025 + + +20110606: commit avant transfert dans git +----------------------------------------- + +* XMED: svn revision 53 + +Les parties de MED utiles à MEDOP seront reversées dans XMED +dans une première étape, puis le tout dans MED 6 au final. diff --git a/src/MEDOP/doc/sphinx/medop-workingnotes-2011.rst b/src/MEDOP/doc/sphinx/medop-workingnotes-2011.rst new file mode 100644 index 000000000..2c38e64bb --- /dev/null +++ b/src/MEDOP/doc/sphinx/medop-workingnotes-2011.rst @@ -0,0 +1,473 @@ +.. meta:: + :keywords: maillage, champ, manipulation + :author: Guillaume Boulant + +.. include:: medop-definitions.rst + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +ANNEXE: Note de travail concernant le chantier XMED 2011 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +.. contents:: Sommaire + :local: + :backlinks: none + +Cas d'utilisation métier +======================== + +On illustre par un exemple (Christophe Vallet, R&D/MMC, 1/7/2011):: + + J'ai souvent des fichiers med de résultats de calcul, et j'aimerais y + ajouter de nouveaux champs issus de champs existants. J'aimerais + aussi pouvoir créer de nouveaux meds plus petits par extraction de + certaines composantes de champs, certains groupes ou certains pas de + temps. + +On peut exprimer le besoin sous la forme des cas d'utilisation +suivants (use cases): + +* **UC1: combiner dans un même fichier med des champs issus de + plusieurs sources de données**. On peut par exemple charger un + premier fichier, puis ajouter à cette base des champs issus d'autre + fichiers ou générés par manipulation de champs, ou encore générés + par un module de calcul qui produirait directement du MEDCoupling. +* **UC2: créer un champ contenant certaines composantes d'un autre + champ**. On pense ici aux fonctions de restriction, qui permettraient + de récupérer certaines composantes uniquement. +* **UC3: créer un champ contenant certains pas de temps d'un autre + champ**. C'est un cas particulier des fonctions de restriction + évoquées ci-dessus. +* **UC4: créer un champ comme la limitation d'un autre champ à un + groupe de mailles**. C'est un cas particulier des fonctions de + restriction évoquées ci-dessus. Notion de domaine spatial. A + priori la notion de groupe est définie dans MEDLoader. + +On peut ajouter également les UC identifiés pour la maquette 2010: + +* **UC5: comparer des champs issus de source de données différentes**, + par exemple des champs chargés de deux fichiers med différents et + qui s'appuient sur le même maillage (au moins conceptuellement). Le + problème technique ici est de pouvoir changer le maillage d'un + champ, pour ramener tous les champs sur le même maillage (au sens + informatique). Ceci est une contrainte de MEDCoupling, les + opérations sur des champs A et B imposent que A et B soient définis + sur le même maillage, i.e. le même objet informatique. +* **UC6: créer un champ de toute pièce sur un maillage**, ou un groupe + de mailles. Ce cas d'usage est typiquement prévu pour produire les + conditions de chargement initial d'une structure. Il s'agit ici + d'initialiser un champ à partir de zéro sur une surface prédéfinie + de la géométrie (par exemple spécifiée par un nom de groupe de + mailles). + +Pour UC5: les sources de données sont référencées dans l'object +browser. On importe explicitement les données dans l'espace de +travail. On peut détecter que les maillages sont identiques et on +propose à l'utilisateur de transférer le champ sur le maillage déjà +présent. Sinon, les champs devront être référencés sur des maillages +distincts dans l'arbre de l'espace de travail. + +Analyses préliminaires pour le chantier 2011 +============================================ + +On fait le choix pour le chantier 2011 de travailler à partir de la +bibliothèque MEDCoupling (et non plus MEDMEM comme c'était le cas dans +le démonstrateur 2011). + +Analyse de MEDCoupling et MEDLoader +----------------------------------- + +MEDCoupling est l'implémentation du modèle de données MED (avec +recherche de minimisation des dépendances logicielles) et MEDLoader +fournit une ensemble de fonctions pour le chargement des structures +MEDCoupling depuis un fichier ou inversement leur sauvegarde sous +forme de fichiers. + +Dans l'implémentation MEDCoupling, un champ est l'ensemble des valeurs +d'une grandeur physique sur un maillage pour un pas de temps donné. Un +champ est caractérisé par: + +* un support spatial, le maillage +* un type de discrétisation spatial, défini par l'emplacement des + valeurs sur le maillage (sur les noeuds, sur les cellules, aux + points de gauss, ...) et le mode d'interpolation spatial (P0, P1, + etc) +* un pas de temps, défini par deux entiers (iteration, order) et un + réel (timestamps) + +Dans cette implémentation, il existe une association 1..n entre un +maillage et un champ (alors que dans MEDMEM, la structure +intermédiaire SUPPORT est implémentée). + +MEDCouplingCorba fournit un ensemble de servants CORBA pour manoeuvrer +des structures MEDCoupling au travers du bus CORBA. L'interface à ce +jour est délibérément réduite. Des classes dites "Cliente" sont +fournies pour piloter les servants CORBA depuis un contexte +client. Par exemple ``MEDCouplingFieldDoubleClient`` fournit une +fonction de création d'une structure MEDCoupling à partir d'un +pointeur vers un servant CORBA. La structure est créée localement +(dans le contexte client) avec duplication des données issue de la +structure encapsulée par le servant CORBA (récupération par la +fonction de sérialisation). + +Aucune interface CORBA n'est défini pour MEDLoader. + +Questions: + +* Voir comment sont créés les servants, et surtout comment ils sont + récupérés (via le lcc?) +* Comment peut-on définir un champ sur un groupe de mailles (et non + pas sur le maillage complet)? Comment peut-on extraire le champs + circoncit à une groupe de mailles pour des opérations. + + - R: méthode changeUnderlyingMesh + +* Comment manipuler deux champs chargées de fichiers différents mais + construit sur le même maillage (conceptuellement). On peut forcer la + réassociation d'un champ sur un autre maillage? +* Manipuler des champs de pas de temps différents? Différentes + composantes d'un ou plusieurs champs? +* Comment importer un MedCoupling dans PARAVIS? (dans VISU?)? + +* mapper sur une image + +Improvments: + +* MEDLoader::Write should raise an exception if the filepath is not writable +* MEDDataManager: développer une classe chapeau sur MEDCoupling et + MEDLoader pour aider au chargement et la gestion de données MED + (orienté manipulation de champs). Cette classe serait associée des + structures légères FieldHandler et MeshHandler et des listes + correspondantes pour la navigation dans les méta-données. +* Sur base du MEDDataManager, prévoir des ports med pour yacs par + lesquels pourrait transiter des handler. + +Nouveaux concepts à prendre en compte +------------------------------------- + +Au démarrage du chantier 2011, on observe que les concepts suivants +sont introduits dans le module MED: + +* Le conteneur MED n'existe plus, utiliser MEDFILEBROWSER pour charger + les fichiers med et obtenir les informations générales sur le + contenu. +* MEDFILEBROWSER: remplace le concept de driver et fournit les + fonctions précédemment fournies par la classe MED pour obtenir les + informations de structure. +* Concept d'Extractor pour une lecture sélective des données de champs + (suivant un critère d'extraction) +* Il n'est plus nécessaire d'appeler les méthodes read explicitement + sur les objets (MESH et FIELD) pour charger les données. Par + ailleurs, on peut définir deux fois le même champs (double + chargement a priori) sans lever d'exception). + + +Analyse de conception pour le chantier 2011 +=========================================== + +Composants SALOME (interfaces IDL) +---------------------------------- + +* MEDDataManager: défini une structure FIELD pour identifier un champ + dans les requêtes. Il s'occupe également de la récupération physique + des données, quelqu'en soit la source (fichier avec MEDLoader, autre + module SALOME comme PARAVIS avec une méthode à définir) +* MEDCalculator: s'occupe des requêtes de calcul dont les arguments sont + les structures FIELD du MEDDataManager. Reprendre l'interface de + MEDOP. + +Use case à réaliser depuis un client python: + +* UC01: ajouter un fichier d'entrée et accéder aux informations + concernant les champs. Ex: récupérer une structure champs par la + donnée des paramètres primaires (nom identifiant, dt, it, nom du + maillage). +* UC02: créer des champs et les ajouter au MEDDataManager +* UC03: mener des opérations basique sur les champs en console python + +Interface Utilisateur +--------------------- + +L'interface utilisateur est composée des parties suivantes: + +* une partie GUI (appelée par la suite MEDGUI) qui s'occupe de piloter + le chargement des données dans l'espace de travail, au moyen d'une + interface graphique; +* une partie TUI (appelée par la suite MEDTUI) qui s'occupe de piloter + la création de champs, au moyen de commandes exécutées dans la + console python. + +Le principe est que les champs sont préalablement chargés au niveau du +composant SALOME au moyen de l'interface graphique (MEDGUI), puis +manoeuvrés depuis l'application SALOME au moyen de variables proxy +définies dans la console python (MEDTUI). Au chargement, les champs +sont indéxés par le MEDDataManager, puis les index sont rendus +accessibles au niveau du GUI au moyen d'une représentation +arborescente de la structure MED. Les feuilles de l'arbre +correspondent à des champs qui peuvent être sélectionnés et dont +l'index peut être obtenu de la sélection. + +L'espace de travail est organisé autour du concept de +"workspace". L'étude SALOME liste les datasource (les fichiers source +des données med, mais peut-être aussi les référence vers des objets +MED déjà existants ou chargé dans PARAVIZ). Une vue complémentaire +permet de voir la structure fine d'une source de données. + +Concernant MEDGUI: + +* la représentation des données (les champs et les maillages associés) + doit permettre de récupérer par l'interface graphique les + identifiants des champs à manipuler (a priori les structures FIELD + définies par le composant MEDDataManager). Cela conduit à la mise en + place des composants suivants: + + - MedDataModel hérité de TreeData. Il est peuplé avec les + méta-données décrivant la structure MED explorée. + - MedGuiManager qui permet l'implantation du doc widget de + présentation + +TODO: + +* specifier le concept de workspace (qui a une entrée dans l'étude?) + en bijection avec un datamanager +* identifier des interlocuteur/utilisateur pour l'aspect ergonomie d'usage + +Concernant MEDTUI: + +* Il fournit les classes FieldProxy + +Questions: + +* Comment traiter le cas du travail sur des composantes ciblées, plus + généralement, comment introduire le concept de domaine + d'application? +* Prévoir des fonctions génériques (initialisation d'un champ sur un + maillage avec une fonction analytique de la position, sauvegarder + les champs créés dans un fichier med) + + +Tâches de développement +======================= + +T20110622.1: Gestion des données internes +----------------------------------------- + +**Status: terminé.** +Suite: fonction de sauvegarde au niveau graphique également + +On vise les cas d'utiliation suivants: + +* UC1: intégrer dans le datamodel du gui un champ créé dans la console + python (et donc présent dans le datamanager du composant). Définir + l'utilité? +* UC2: renommer un champ et plus généralement changer ses méta-données + (avec assurance de synchronisation entre toutes les données). +* UC3: sauvegarder une sélection de champs. La sélection peut se faire + dans l'arbre du datamodel gui. + +WARN: robustesse de fieldproxy + + + +T20110622.2: UC Initialisation/Création de champs +------------------------------------------------- + +**Status: à faire** + +Les cas implémentés à ce jour sont la création de champs à partir de +champs existants et chargés d'un fichier med. On souhaite ici réaliser +des cas 'utilisation autour de la création de champs "from scratch", +s'appuyant tout de même sur un maillage chargé. + +UC01: Sélection d'un groupe de maille dans SMESH pour initialiser un +champ (par exemple les conditions limites d'un problème de calcul). + +UC02: créer un champ avec des restrictions qui définissent le domaine +d'application des opération de champs. + +UC03: créer un champ à partir d'une image (codes rgb utilisé comme les +composantes du champs vectoriel ou niveaux de gris pour un champ +scalaire. Attention, pour ça, il faudra a priori fiare une projection +du maillage cartesien de l'image sur le maillage (quelconque) sur +lequel on souhaite définir le champ. + +UC04: créer un champ à partir d'un tableau numpy + +De manière générale, ce type de création sera assisté par le +MEDGUI. Au niveau MEDTUI, les fonctions pourraient être fastidieuses +pour l'utilisateur. + +Par exemple, prévoir un menu contextuel qui propose les opérations +possibles en fonction de la sélection (en plus de la fonction d'import +dans la console python). + +TODO: + +* développer les fonctions d'initialisation, par exemple au moyen + d'applyFunc et du mécanisme de callable? + +T20110622.3: documentation contextuel +------------------------------------- + +**Status: à faire** + +* Remettre toutes les commandes dans le même fichier (fusionner cmdtools + et fieldtools) +* Faire un modèle générique de command (classe de base +* Batir la doc des commandes sur cette base (lister toutes les + instances de type Command par exemple) + +T20110622.4: remontée des exception du composant MEDCalculator +-------------------------------------------------------------- + +**Status: en cours, compléter la couverture** + +Pour des messages contextuel sur les erreurs de calcul (ex: division +par 0) + +* Poursuivre le travail fait sur getMedEventListener +* Protéger tous les appels au composants effectués depuis la console + python (prendre example sur la commande save) + +T20110624.1: gestion des données GUI +------------------------------------ + +**Status: à faire** + + + +Le workspace a une entrée dans l'obrowser. Sur cette entrée on peut: + +* supprimer: supprime tout les champs associés +* sauvegarder. Dans ce cas, on rappelle l'ensemble des champs pour + cocher ceux qu'on veut sauvegarder. + +Le gui data model est réservé aux opérations sur les champs et à +piloter leur import dans la console python. + +TODO: + +* Spécifier les concepts de workspace, database, et datasource, espace + de gestion, ... et les associations. Simplifier avec l'appuie de use + cases. +* Mécanisme de mise à jour du TreeView de XSALOME (aujourd'hui, seul + l'ajout addChild est implémenté +* Clic droit sur objets de l'arbre: dans la notification TreeView -> + WorkspaceController, faire remonter l'évènement clic droit ainsi que la + liste des éléments sélectionné pour faire générer le menu contextuel + au niveau du WorkspaceController qui peut déterminer le contexte métier + (le TreeView ne le connaît pas). +* Définir des DataObject pour les maillages, les séries temporelles et + les champs + + +Spécification des espaces de données: + +* MEDDataManager dépend de l'étude (pour permettre la publication + d'information dans une étude SALOME). +* créer "sourcid = MEDDataManager::addDataSource(filename)", suivie de + requetes getFields(sourceid), getMeshes(sourceid) +* les espaces de données: dataspace, workspace. Un seul workspace par + étude, mais autand de datasources que l'on souhaite dans le + dataspace. Les datasources sont rangés dans l'étude (le dataspace) + et sont non modifiables après chargement (référence des sources de + données). + + +T20110628.1: extention à d'autres objets SALOME +----------------------------------------------- + +**Status: suspendu** + +On doit reposer la question de l'existance de l'arbre indépendant +(DockWidget), d'une part, et l'extention aux autres objets (GEOM et +SMESH en particulier) du principe de sélection graphique pour +utilisation dans la console python, d'autre part. + + +T20110628.2: visualisation d'un champ avec PARAVIS +-------------------------------------------------- + +**Status: terminé (pour une première version)** +Suite: de nombreux défauts subsistent + +Questions/remarques: + +* Pb au démarrage du module: VisTrails fails to start +* Peux-t-on piloter la vue 3D sans charger le module? (voir + myparavis.py) +* Comment donner un nom au MEDReader1 dans l'arbre Pipeline? +* Comment utiliser directement les objets MEDCouplingField? + + +T20110706.1: documentation du module +------------------------------------ + +**Status: en cours (10%)** + +Documenter les commandes TUI puis l'utilisation générale de +l'interafce graphique. Mentionner l'existance de la commande medop.sh +pour travailler exclusivement en mode texte (utile pour les tests +rapides). + +Documenter les modalités d'exécution des tests. + +T20110708.1: helper python pour MEDCoupling +------------------------------------------- + +**Status: en attente (pas urgent)** + +Faire un helper python dans le package xmed qui permet de faire du +medcoupling facilement (essentiellement pour simplifier le chargement, +puis la sélection des données). Cela demanderait de faire un +MedDataManager comme une class C++ pure (non CORBA). Cette classe +travaillerait par exemple uniquement avec des id et des liste d'id, et +fournirait des fonctions d'affichage (comme le ``ls`` et le ``la``) +pour obtenir des meta-information. + +Le servant MedDataManager pourrait être une surcouche de cette classe +c++ pure. + +T20110708.2: analyses et tests +------------------------------ + +TODO: + +* créer un fichier de test avec plusieurs pas de temps +* créer un fichier de test avec des groupes de mailles + + +T20110728.1: refactoring MEDDataManager +--------------------------------------- + +Refactoring pour une meilleur association entre FieldHandler et MeshHandler: + +* dans la mesure du possible utiliser les id plutôt que les handler en + arguments des fonctions d'appel des objets +* A chaque champ (FieldHandler), on doit associer un meshid (et de + manière optionnelle un fieldseriesId, si le champ peut être associé + à une serie temporelle. A priori faisable uniquement au chargement + du datasource). +* Pour cela, revoir les fonctions internes newFieldHandler et addField + ou prévoir de les compléter à chaque fois qu'elles sont appelée avec + les informations concernant le meshid. +* addField est utilisée par le MEDCalculator +* Attention au raffraichissement des données handler au niveau du + Workspace. Peut-être le mieux est que les fieldproxy contiennent + uniquement le fieldid, et qu'ils interroge le datamanager à chaque + fois qu'ils ont besoin d'une donnée. Voir aussi les notifications + via le MEDEventListener? **Le plus simple est de faire la mise à + jour lors de l'appel à la méthode __repr__ du fieldproxy, i.e. quand + on essaye d'afficher les données**. Parceque sinon il n'y a pas de + problème puisque que le calculateur travaille à partir des id. + + +Petites améliorations du DataspaceController: + +* Au OnUseInWorkspace, stocker (dans la mesure du possible) le nom de + l'alias python dans un attribut du sobject. +* Dans DlgChangeUnderLyingMesh, expliquer que le champs sera dupliquer + est posé dans le WS. On peut donc proposer en option de lui associer + un alias pour manipulation dans la console + + + diff --git a/src/MEDOP/doc/sphinx/medop-workingnotes-2012.rst b/src/MEDOP/doc/sphinx/medop-workingnotes-2012.rst new file mode 100644 index 000000000..b6ecb6d37 --- /dev/null +++ b/src/MEDOP/doc/sphinx/medop-workingnotes-2012.rst @@ -0,0 +1,84 @@ +.. meta:: + :keywords: maillage, champ, manipulation + :author: Guillaume Boulant + +.. include:: medop-definitions.rst + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +ANNEXE: Note de travail concernant le chantier XMED 2012 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +.. contents:: Sommaire + :local: + :backlinks: none + + +Analyse preliminaire pour le chantier 2012 +========================================== + +La figure imposée pour le chantier 2012 est l'intégration du nouveau +module de manipulation de champs dans SALOME 6.6 (objectif CEA), en +préparation de la mise en exploitation dans SALOME 7 (objectif EDF). + +L'état actuel est: + +* Un module SALOME de nom MED intégrant les bibliothèques MEDCoupling, + MEDLoader, REMAPPER, mais aussi plusieurs packages logiciels + aujourd'hui obsolètes ou amener à disparaître pour l'échéance + SALOME7 +* Un module SALOME de nom XMED qui fournit les fonctions graphiques + pour la manipulation de champs. +* Ce module XMED utilise le module VISU pour les vue de contrôle. + +La cible est: + +* Un module unique (nom à définir, par exemple MEDOP) débarrassé des + packages logiciels obsolètes et intégrant les fonctions graphiques + (GUI et TUI). +* L'utilisation du module PARAVIS (au lieu de VISU) pour les vues de + contrôle. +* L'intégration de MEDCoupling avec YACS (port MED dans YACS par + exemple). + +A examiner: + +* voir les attendus concernant les ports MED dans YACS +* interface PARAVIS: utilisation du viewer (et de l'API python) sans chargement du GUI + +Tâches de développement +======================= + +20120904: Migrer XMED dans MED +------------------------------ + +Plan de travail: + +* Migration des composants + test + + + +20120904: Nettoyage de XSALOME +------------------------------ + +:status: en cours + +* Supprimer les vieilleries de XSALOME: + + - StdHelper -> Basic_Utils (KERNEL) + +20120829: mise en place du chantier 2012 +---------------------------------------- + +:status: terminé + +L'objectif de cette première étape est de reverser le prototype 2011 +(module XMED indépendant) dans la branche V6_main du module MED. On +peut procéder de la manière suivante: + +* update de XMED (et XSALOME utilisé par XMED) pour fonctionnement sur + V6_main +* Eliminer la dépendance à XSALOME +* Supprimer la gestion des multiversion SALOME5/6 au niveau de l'engine + +.. warning:: TODO: refaire le point sur les tâches initiées en 2011 + diff --git a/src/MEDOP/doc/sphinx/salomedoc.rst b/src/MEDOP/doc/sphinx/salomedoc.rst deleted file mode 100644 index fc2f1fdc8..000000000 --- a/src/MEDOP/doc/sphinx/salomedoc.rst +++ /dev/null @@ -1,231 +0,0 @@ -.. meta:: - :keywords: SALOME, development - :author: Guillaume Boulant - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Annexe : Règles de développement SALOME -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -Cette annexe est un recueil de techniques de développement spécifiques -à l'environnement SALOME et utilisées pour la mise au point du module -XMED. Elles sont a priori utilisables pour d'autres contexte de -développement dans SALOME. - -.. TODO: récupérer les fonctions génériques de VisuGUI_Tools.cxx -.. TODO: récupérer les fonctions génériques de SMESGGUI_utils.cxx - -.. contents:: Sommaire - :local: - :backlinks: none - -Récupérer la sélection dans l'arbre d'étude -=========================================== - -Dans une classe dérivée de ``SalomeApp_Module``, on peut utiliser un -code de la forme suivante: - -.. code-block:: cpp - - #include - #include - #include - #include - - // ... - - // Get the selected object in the study (SObject) - LightApp_SelectionMgr* aSelectionMgr = this->getApp()->selectionMgr(); - SALOME_ListIO aListIO; - aSelectionMgr->selectedObjects(aListIO); - - // Analyse the selection. There can be more than one item. - SALOME_ListIteratorOfListIO It (aListIO); - for (; It.More(); It.Next()) { - Handle(SALOME_InteractiveObject) anIO = It.Value(); - SALOMEDS::SObject_var aSObject = aStudy->FindObjectID(anIO->getEntry()); - - // Check if the selected object is relevant for the operation - // ... - - // Process the SObject if it's relevant - // ... - - } - -On peut noter qu'une variable ``aStudy`` est requise. Elle représente -l'étude SALOME sur laquelle s'oppère la sélection. L'étude active -(impliquée dans la sélection) peut être obtenue au moyen du -gestionnaire d'étude (voir :ref:`ci-dessous `). - -Réglage du curseur graphique -============================ - -Dans le cas où le traitement est long, il peut être intéressant -d'encadrer l'opération par un vérouillage du curseur de sélection: - -.. code-block:: cpp - - QApplication::setOverrideCursor(Qt::WaitCursor); - - // Do the job - // ... - - QApplication::restoreOverrideCursor(); - - -Les variables pour la gestion de l'étude -======================================== - -Les variables CORBA -------------------- - -Les variables CORBA comme le serveur de noms (naming service) et le -gestionnaire de cycle de vie des objets (LifeCycleCRORBA) sont -fréquement utilisés. Dans le contexte d'une application (classe de -type ``SalomeApp_Module``), il est possible de récupérer simplement -des instances de ces variables par les commandes suivantes: - -.. code-block:: cpp - - #include - #include - - CORBA::ORB_var orb = SalomeApp_Application::orb(); - SALOMEDSClient_StudyManager* studyMgr = SalomeApp_Application::studyMgr(); - SALOME_NamingService* namingService = SalomeApp_Application::namingService(); - SALOME_LifeCycleCORBA* lcc = SalomeApp_Application::lcc(); - -Pour un usage en dehors de l'application graphique (par exemple au -niveau du container), l'orb peut être obtenu par les mécanismes -standard d'omniORB: - -.. code-block:: cpp - - CORBA::ORB_var orb = CORBA::ORB_init(0,0); - -L'orb est par exemple utile à récupérer pour la sérialisation des -objets CORBA et la manipulation des références sous forme de chaîne de -caractères: - -.. code-block:: cpp - - // We suppose here that we have a CORBA object reference (object of - // type *_ptr or *_var), for example a SALOME_MED::MED object. - SALOME_MED::MED_ptr medObj = ... // anything to get this object - QString medIOR = orb->object_to_string(medObj); - - SALOME_MED::MED_ptr anOtherRefToMedObj = orb->string_to_object(medIOR) - -.. note: this serialization can be used to communicate between a GUI - and a component in a container, or between the C++ context and the - python context. - -.. _salomedoc_getActiveStudy: - -Récupérer l'étude active ------------------------- - -Le concept d'étude active est un concept GUI. Il désigne l'étude en -cours d'usage au niveau de l'interface graphique. - -.. note: Pour rappel, l'étude est un objet CORBA de type - ``SALOMEDS::Study`` qui héberge physiquement les ``SObject`` - pointant vers les données. L'arbre d'étude ("Object browser") est - une représentation graphique de cet objet. - -L'étude active peut être obtenue au moyen du gestionnaire -d'étude. Dans le corps d'une classe de type ``SalomeApp_Module``, ceci -peut se faire par un code de la forme suivante: - -.. code-block:: cpp - - #include "SALOMEconfig.h" - #include CORBA_SERVER_HEADER(SALOMEDS) - #include - #include - - // ... - - // Get the study id of the active study - SalomeApp_Study* appStudy = dynamic_cast (this->getApp()->activeStudy()); - _PTR(Study) aCStudy = appStudy->studyDS(); - int aStudyID = aCStudy->StudyId(); - - // Then get the study manager - SALOME_NamingService *aNamingService = SalomeApp_Application::namingService(); - CORBA::Object_var anObject = aNamingService->Resolve("/myStudyManager"); - SALOMEDS::StudyManager_var aStudyManager = SALOMEDS::StudyManager::_narrow(anObject); - - // Finally, request the study manager for the study (SALOMEDS::Study) - SALOMEDS::Study_var aStudy = aStudyManager->GetStudyByID(aStudyID); - - -Communiquer avec la console python -================================== - -La console python désigne l'interpréteur embarqué dans l'interface -graphique de SALOME (GUI). Elle est également désignée comme -l'interface textuelle de SALOME (TUI) car elle permet de piloter -SALOME au moyen de commandes en syntaxe python. - -Le paragraphe montre comment communiquer avec cette interface texte -depuis le contexte C++ de l'interface graphique, en particulier pour -déclencher l'exécution de commandes. - -Le code se situe donc au sein d'une classe de type -``SalomeApp_Module`` (de laquelle hérite la partie graphique d'un -module SALOME, de nom ``GUI``). Cette classe possède une -méthode ``getApp()`` par laquelle on peut récupérer une instance de la -console python embarquée (this->getApp()->pythonConsole()). - -Le code suivant illustre l'envoie d'une commande python par ce -mécanisme. Dans cette exemple, on défini une variable ``id`` dans la -console python comme l'identifiant de l'étude active: - -.. code-block:: cpp - - #include - #include - #include - - PyConsole_Console * pyConsole = getApp()->pythonConsole(); - - QStringList commands; - commands+="import salome"; - commands+="id=salome.myStudyId"; - - QStringListIterator it(commands); - while (it.hasNext()) { - pyConsole->exec(it.next()); - } - -Dans ce deuxième exemple, on cherche à reconstituer dans le contexte -de la console python un pointer vers un objet med instancié dans le -contexte C++ de l'application graphique. Pour cela, on communique la -référence de l'objet sous la forme sérialisé (IOR pour un objet -CORBA): - -.. code-block:: cpp - - #include - #include - #include - #include - - // We suppose here that we have a CORBA object reference (object of - // type *_ptr or *_var), for example a SALOME_MED::MED object. - SALOME_MED::MED_ptr medObj = ... // anything to get this object - - // Get the IOR of this object - QString medIOR = SalomeApp_Application::orb()->object_to_string(medObj); - - PyConsole_Console * pyConsole = getApp()->pythonConsole(); - - QStringList commands; - commands+="import salome"; - commands+=QString("med=salome.orb.string_to_object(\"%1\")").arg(medIOR); - - QStringListIterator it(commands); - while (it.hasNext()) { - pyConsole->exec(it.next()); - } diff --git a/src/MEDOP/doc/sphinx/xmed-definitions.rst b/src/MEDOP/doc/sphinx/xmed-definitions.rst deleted file mode 100644 index cfd0bc148..000000000 --- a/src/MEDOP/doc/sphinx/xmed-definitions.rst +++ /dev/null @@ -1,88 +0,0 @@ -.. AVERTISSEMENT: -.. Ce fichier contient les définitions globales à la documentation. Il -.. peut être inclu au moyen de la directive rst "include" pour -.. disposer des définitions dans le fichier qui fait l'inclusion. -.. Pour éviter de polluer les textes dans lequel ce fichier est inclu, -.. il est interdit de faire afficher du texte par ce document de -.. définition. - -.. REFERENCES DOCUMENTAIRES: -.. (les documents sont fournis dans le répertoire _static/documents) - -.. You can refer to this reference using the keyword: |REF_EDF_VCA_H-I2C-2009-03595-FR|_ -.. |REF_EDF_VCA_H-I2C-2009-03595-FR| replace:: H-I2C-2009-03595-FR: Manipulation de champs dans SALOME - Orientations générales -.. _REF_EDF_VCA_H-I2C-2009-03595-FR: _static/documents/20091218_EDF_VCANO_H-I2C-2009-03595-FR.pdf - -.. You can refer to this reference using the keyword: |REF_CEA_VBE_MEDMEM|_ -.. |REF_CEA_VBE_MEDMEM| replace:: Guide utilisateur de MED mémoire -.. _REF_CEA_VBE_MEDMEM: _static/documents/20070105_CEA_VBERGEAUD_GuideutilisateurMEDMEMOIRE.pdf - -.. You can refer to this reference using the keyword: |REF_EDF_GBO_WORKNOTE|_ -.. |REF_EDF_GBO_WORKNOTE| replace:: XMED: Notes de travail -.. _REF_EDF_GBO_WORKNOTE: _static/documents/20110309_XMED_scan_notes.pdf - -.. You can refer to this reference using the keyword: |REF_EDF_ELO_REM|_ -.. |REF_EDF_ELO_REM| replace:: XMED: Remarques E. Lorentz -.. _REF_EDF_ELO_REM: _static/documents/20110309_XMED_scan_remarques_ELORENTZ.pdf - -.. You can refer to this reference using the keyword: |REF_EDF_PRESMANIPCHP01|_ -.. |REF_EDF_PRESMANIPCHP01| replace:: Séminaire EDF-CEA de janvier 2010: manipulation de champs -.. _REF_EDF_PRESMANIPCHP01: _static/documents/20100129_MAN_seminaireEDF-CEA_all.pdf - -.. You can refer to this reference using the keyword: |REF_EDF_PRESMANIPCHP02|_ -.. |REF_EDF_PRESMANIPCHP02| replace:: Révue EDF-CEA: maquette de manipulation de champs -.. _REF_EDF_PRESMANIPCHP02: _static/documents/20101027_MAN_revueEDF-CEA.pdf - -.. You can refer to this reference using the keyword: |REF_EDF_PRESMANIPCHP03|_ -.. |REF_EDF_PRESMANIPCHP03| replace:: Séminaire EDF-CEA de mars 2011: manipulation de champs, maquette 2010 -.. _REF_EDF_PRESMANIPCHP03: _static/documents/20110310_seminaireEDF-CEA_maquetteXMED.pdf - -.. PRESENTATIONS: - -.. You can refer to this reference using the keyword: |REF_EDF_JUS2011_PDF|_ -.. |REF_EDF_JUS2011_PDF| replace:: JUS2011: outils de manipulation de champs -.. _REF_EDF_JUS2011_PDF: _static/presentations/20111115_JUS-2011/20111115_JUS2011_manipulation_de_champs.pdf - -.. You can refer to this reference using the keyword: |REF_EDF_JUS2011_OGV1|_ -.. |REF_EDF_JUS2011_OGV1| replace:: JUS2011: outils de manipulation de champs - Exemple 1 -.. _REF_EDF_JUS2011_OGV1: _static/presentations/20111115_JUS-2011/20111115_JUS2011_medop_exemple_1.ogv -.. You can refer to this reference using the keyword: |REF_EDF_JUS2011_OGV3|_ -.. |REF_EDF_JUS2011_OGV3| replace:: JUS2011: outils de manipulation de champs - Exemple 3 -.. _REF_EDF_JUS2011_OGV3: _static/presentations/20111115_JUS-2011/20111115_JUS2011_medop_exemple_3.ogv -.. You can refer to this reference using the keyword: |REF_EDF_JUS2011_OGV4|_ -.. |REF_EDF_JUS2011_OGV4| replace:: JUS2011: outils de manipulation de champs - Exemple 4 -.. _REF_EDF_JUS2011_OGV4: _static/presentations/20111115_JUS-2011/20111115_JUS2011_medop_exemple_4.ogv - - - -.. LIENS EXTERNES: -.. (l'accès nécessite le réseau intranet EDF et internet) - -.. You can refer to this reference using the keyword: |LINK_EDF_MEDDOC|_ -.. |LINK_EDF_MEDDOC| replace:: Modèle MED -.. _LINK_EDF_MEDDOC: http://med.der.edf.fr/logiciels/med-2.3.6/doc/html/modele_de_donnees.html - -.. You can refer to this reference using the keyword: |LINK_EDF_MEDFICHIERDOC|_ -.. |LINK_EDF_MEDFICHIERDOC| replace:: Documentation de MED fichier -.. _LINK_EDF_MEDFICHIERDOC: http://med.der.edf.fr/logiciels/med-2.3.6/doc - -.. You can refer to this reference using the keyword: |LINK_EDF_SALOME_MED__MED|_ -.. |LINK_EDF_SALOME_MED__MED| replace:: SALOME_MED::MED -.. _LINK_EDF_SALOME_MED__MED: http://nepal.der.edf.fr/pub/SALOME_userguide/MED5/doc/salome/tui/MED/interfaceSALOME__MED_1_1MED.html - -.. RENVOIES: - -.. You can refer to this reference using the keyword: |SEE_MEDMEM_CORBA| -.. |SEE_MEDMEM_CORBA| replace:: :ref:`L'interface CORBA SALOME_MED` - - -.. SNAPSHOTS: - -.. |XMED_SPECIFICATIONS_PDF| replace:: version pdf -.. _XMED_SPECIFICATIONS_PDF: _static/documents/xmed-specifications.pdf - -.. |XMED_DEVELGUIDE_PDF| replace:: version pdf -.. _XMED_DEVELGUIDE_PDF: _static/documents/xmed-develguide.pdf - -.. |XMED_USERGUIDE_PDF| replace:: version pdf -.. _XMED_USERGUIDE_PDF: _static/documents/xmed-userguide.pdf diff --git a/src/MEDOP/doc/sphinx/xmed-develguide.rst b/src/MEDOP/doc/sphinx/xmed-develguide.rst deleted file mode 100644 index be5d72bab..000000000 --- a/src/MEDOP/doc/sphinx/xmed-develguide.rst +++ /dev/null @@ -1,239 +0,0 @@ -.. meta:: - :keywords: maillage, champ, manipulation, med, développement - :author: Guillaume Boulant - -.. include:: xmed-definitions.rst - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Module XMED: Guide de développement -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -(|XMED_DEVELGUIDE_PDF|_) - -Ce document est la documentation technique du module XMED. Il fournit -les instructions à suivre pour installer le module en vue d'un travail -de développement, puis décrit les éléments de conception qui -structurent le module. - -.. contents:: Sommaire - :local: - :backlinks: none - -.. warning:: Ce document est en travaux. Tant que cet avis n'aura pas - disparu, veuillez en considérer le plan et le contenu encore - incomplets, temporaires et sujets à caution. - -Mise en place d'un espace de développement -========================================== - -Gestion de configuration du module XMED ---------------------------------------- - -Les sources du module (répertoire ``xmed``) sont archivés en dépôt de -configuration dans une base git du projet NEPAL. Ils peuvent être -récupérés au moyen de la commande:: - - $ git clone git@cli70rw.der.edf.fr:xom/xmed.git - -Cette commande installe un répertoire ``xmed`` contenant l'ensemble -des sources du module XMED. - -Le module XMED a pour pré-requis logiciel la plateforme SALOME: - -* SALOME version 6.1.3 (au moins) à télécharger à l'URL - http://pal.der.edf.fr/pal/projets/pal/releases/V6_1_3 -* On peut également utiliser une version dérivée comme SALOME-MECA 2010.1 -* Installer la plate-forme choisie selon les instructions fournies. - -Le module XMED utilise également une bibliothèque interne au projet -NEPAL, appelée XSALOME, et qui fournit une extension aux fonctions de -SALOME pour un usage de développement (XSALOME signifie eXtension -SALOME). Les sources de cette bibliothèque doivent être récupérés au -moyen de la commande:: - - $ git clone git@cli70rw.der.edf.fr:xom/xsalome.git - -Cette commande installe un répertoire ``xsalome`` contenant l'ensemble -des sources de la bibliothèque XSALOME. - -.. note:: La bibliothèque XSALOME n'est pas un module SALOME mais une - simple bibliothèque de fonctions qui complète ou rend plus facile - d'utilisation les fonctions de SALOME. Elle NE DOIT EN AUCUN CAS - être intégrée à d'autres projets que les projets internes NEPAL ou - MAILLAGE. Il s'agit en effet d'une bibliothèque de transition qui - héberge des développements destinés à être reversés dans la - plate-forme SALOME. Le contenu et les interfaces de XSALOME ne peut - donc être garanti sur le long terme. - -Installation et lancement de l'application ------------------------------------------- - -L'installation suppose qu'une version 6.1.3 de SALOME (ou plus) est -disponible et que le shell de travail est étendu avec l'environnement -de SALOME. En général, par des commandes de la forme:: - - $ . /where/is/salome/prerequis.sh - $ . /where/is/salome/envSalome.sh - -La compilation des modules xsalome et xmed suit le standard SALOME. La -bibliothèque xsalome est un prérequis à la compilation de xmed. Pour -cela, la variable d'environnement XSALOME_DIR doit être spécifiée pour -la configuration de la procédure de reconstruction de xmed:: - - $ export XSALOME_DIR= - -Aprés l'installation de xmed, il est possible de générer -automatiquement une application SALOME prête à l'emploi pour la -manipulation de champs:: - - $ /bin/salome/xmed/appligen/appligen.sh - -Cette commande génére un répertoire ``appli`` à l'emplacement où elle -est exécutée. Il reste à lancer l'application SALOME au moyen de la -commande:: - - $ ./appli/runAppli -k - -Exécution des tests unitaires ------------------------------ - -Les tests unitaires peuvent être exécutés au moyen de scripts python -lancés depuis une session shell SALOME. Dans un nouveau shell, taper:: - - $ ./appli/runSession - [NS=mars:2810]$ python appli/lib/python2.6/site-packages/salome/xmed/test_medoperation.py - -L'exécution imprime un rapport détaillant le résultat pour chaque -fonction de test:: - - test_addition (__main__.MyTestSuite) ... ok - test_arithmetics (__main__.MyTestSuite) ... ok - test_composition (__main__.MyTestSuite) ... FAIL - test_litteral_equation (__main__.MyTestSuite) ... ok - test_modification_of_attributes (__main__.MyTestSuite) ... ok - test_unary_operations (__main__.MyTestSuite) ... ok - test_update_metadata (__main__.MyTestSuite) ... ok - -Les scripts de test sont: - -* ``test_medoperation.py``: tests des operations de champs telles - qu'elles sont mises en oeuvre depuis l'interface textuelle. -* ``test_xmed.py``: tests des composants CORBA mis en oeuvre - (``MEDDataManager`` et ``MEDCalculator``) - -Architecture du module XMED -=========================== - -Le module MED pour la manipulation de champs est composé de: - -* une bibliothèque de fonctions pour le traitement de données sur des - maillages et des champs conformes au modèle MED (package - MEDCoupling, MEDLoader et REMAPPER); -* une interface graphique pour la mise en oeuvre des cas standard de - manipulation de champs; -* une ensemble d'outils pour intervenir sur des fichiers au format - MED. - -Une bibliothèque de fonctions pour le traitement de données ------------------------------------------------------------ - -La figure ci-dessous montre la structure des paquets logiciels qui -constituent la bibliothèque: - -.. image:: images/medlayers.png - :align: center - -Elle comprend en particulier les paquets suivants: - -* MEDCoupling: qui décrit les structures de données pour porter les - maillages et les champs -* MEDLoader: qui fournit les fonctions de persistence sous forme de - fichiers au format MED (lecture et écriture). -* REMAPPER: - -Il est important de noter que MEDCoupling n'a aucune dépendance -logicielle autre que la bibliothèque C++ standard. Ceci permet -d'envisager son implantation dans un code de calcul ou un outil de -traitement sans tirer l'ensemble pré-requis de SALOME. - -Une interface graphique pour l'exécution des cas standard ---------------------------------------------------------- - - -Un ensemble d'outils pour le traitement de fichiers ---------------------------------------------------- - - -Description des composants -========================== - -MEDDataManager - Le gestionnaire des données de session -------------------------------------------------------- - -Le composant MEDDataManager s'occupe de fournir les données MED sur -demande des interfaces clientes, en particulier pour module de -pilotage fieldproxy.py. Ces données peuvent avoir plusieurs sources, -en général elle proviennent d'un fichier au format med contenant des -champs définis sur des maillages. Les données sont identifiées à la -lecture des métadonnées de description dans le fichiers med, puis les -valeurs des champs et les maillages support sont chargés au besoin. - -Le chargement des métadonnées de description se fait par la méthode:: - - addDatasource(const char \*filepath) - - - -Eléments d'implémentation -========================= - -Ecrire un service CORBA qui retourne une sequence de FieldHandler: - -.. code-block:: cpp - - MEDOP::FieldHandlerList * MyFunction(...) { - vector fieldHandlerList; - ... - - fieldHandlerList.push_back(fieldHandler); - - // Map the resulting list to a CORBA sequence for return: - MEDOP::FieldHandlerList_var fieldHandlerSeq = new MEDOP::FieldHandlerList(); - int nbFieldHandler = fieldHandlerList.size(); - fieldHandlerSeq->length(nbFieldHandler); - for (int i=0; iid] = fieldHandler; - - // >>> WARNING: CORBA struct specification indicates that the - // assignement acts as a desctructor for the structure that is - // pointed to. The values of the fields are copy first in the new - // structure that receives the assignement and finally the initial - // structure is destroyed. In the present case, WE WANT to keep - // the initial fieldHandler in the map. We must then make a deep - // copy of the structure found in the map and return the copy. The - // CORBA struct specification indicates that a deep copy can be - // done using the copy constructor. <<< - return new MEDOP::FieldHandler(*fieldHandler); - - - -ANNEXE: Bug en cours -==================== - -TO FIX: - -* la composition d'opérations n'est pas possible (ex: 2*f1+f2) car - 2*f1 est indiqué comme non compatible (il semble qu'il n'ai pas la - reference correcte vers le maillage). -* le script de test test_medoperation.py plante si le module xmed n'a - pas été chargé avec des données chargées. diff --git a/src/MEDOP/doc/sphinx/xmed-prototype-develguide.rst b/src/MEDOP/doc/sphinx/xmed-prototype-develguide.rst deleted file mode 100644 index de2387b74..000000000 --- a/src/MEDOP/doc/sphinx/xmed-prototype-develguide.rst +++ /dev/null @@ -1,731 +0,0 @@ -.. meta:: - :keywords: maillage, champ, manipulation, XMED - :author: Guillaume Boulant - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Démonstrateur XMED, documentation technique -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -Cette note fait la synthèse des développements effectués pour le -maquettage des fonctions de manipulation de champs dans SALOME. Elle -présente les principes retenus en matière de conception, c'est-à-dire -concernant les mécanismes techniques sous-jacents, et en matière -d'ergonomie, c'est-à-dire concernant les modalités d'utilisation dans -l'environnement SALOME. - -Ces principes sont illustrés par des développements implantés dans le -module XMED, développé pour les besoins de l'analyse, et dans le -module MED distribué avec la plateforme SALOME. - -.. note:: la lecture de ce chapitre demande une connaissance de la - structure de classes du module MED, en particulier la distinction - entre les classes ``MEDMEM::*`` et les servants CORBA associés - (classe ``SALOME_MED::*``). - -.. contents:: Sommaire - :local: - :backlinks: none - -Principes directeurs -==================== - -Objectif et motivation ----------------------- - -L'objectif de maquettage est de trouver une architecture technique qui -permet d'exécuter le cas d'utilisation suivant: - -* Chargement d'un fichier med dans SALOME (a priori dans le module MED) -* Sélection graphique des champs de l'étude à mettre à disposition - dans la console utilisateur ("calculette" en mode texte qui - concraitement correspond à l'interface python de SALOME). -* Dans la calculette, exécution d'opérations algébriques (+,-,*,/) - entre champs avec possibilité d'utiliser des scalaires dans des - opérations de type transformation linéaire (y=ax+b ou y et x sont - des champs et a et b des scalaires). Opérations pow, sqrt. -* Possibilité de visualiser les champs produits avec VISU pour - contrôle des résultats. -* Possibilité d'exporter des champs produits dans un fichier med. - -Eléments de contexte --------------------- - -Les opérations de manipulation de champs sont en grande partie -implémentées dans la bibliothèque MEDMEM. Pour illustration, le -fragment de code ci-dessous montre comment une addition de champ peut -être opérée en python: - -.. code-block:: python - - from libMEDMEM_Swig import MedDataManager - from xmed.helper import readMed, writeMed - - # Load the medmem data structure from a med file - med = readMed("/tmp/input.med") - # Then create a med data manager to deal with the fields data - dm = MedDataManager(med) - # Get the timestamps (dt,it)=(-1,-1) of the fields "testfield1" and "testfield2" - f1 = dm.getFieldDouble("testfield1",-1,-1) - f2 = dm.getFieldDouble("testfield2",-1,-1) - - # Create a new field as the sum of f1 and f2 - r = f1 + f2 - # And add this new field to the med data structure - med.addField(r) - - # Finally, write the whole data in an output med file - writeMed(med,"/tmp/output.med") - -Ceci montre que les champs peuvent être manipulés avec une interface -relativement ergonomique (une addition de deux champs f1 et f2 s'écrit -f1+f2) tant que l'on manoeuvre des objets MEDMEM purs (classes C++ du -package MEDMEM et wrapping python du package MEDMEM_SWIG). - -Par ailleurs, le fonctionnement actuel des modules SALOME qui -manoeuvrent des données MED est d'instancier les structures de données -MEDMEM au niveau de la partie serveur, c'est-à-dire au niveau des -servants CORBA hébergés dans le processus ``SALOME_Container``, et de -donner accés à ces données depuis l'étude SALOME au travers de -pointeurs CORBA. Ce choix d'architecture présente l'avantage de -centraliser au niveau serveur la gestion du cycle de vie des données -informatiques et de pouvoir distribuer des "poignées" pour manipuler -ces données depuis chaque point de l'application qui sait accéder au -bus CORBA, l'interface graphique en particulier. - - -Hypothèse de travail --------------------- - -Compte-tenu de l'objectif de maquettage et des éléments de contexte -existant, on cherche une solution dans le cadre des hypothèses -de travail suivantes: - -* La manipulation des champs se fait dans l'environement graphique de - SALOME. -* Dans cet environnement, on souhaite pouvoir sélectionner - graphiquement les champs à considérer, puis manipuler ces champs - dans l'interface texte au moyen de variables python avec une syntaxe - aussi simple que celle définie dans le wrapping python de MEDMEM, - c'est-à-dire que pour faire l'addition de 2 champs f1 et f2, on veut - pouvoir écrire f1+f2. -* Les données MED sont physiquement dans la partie serveur de SALOME - et accessibles via des pointeurs CORBA (interface spécifiée dans - MED.idl). On exclu la recopie de données au niveau du client - graphique. - -Dans le cadre de ces hypothèses, la difficulté technique réside dans -la mise au point d'une interface de communication entre des variables -manipulées par l'utilisateur dans l'interface graphique (c'est-à-dire -dans le processus ``SALOME_SessionServer``) et des objets MEDMEM -instanciés dans le containeur des servants CORBA (c'est-à-dire dans le -processus ``SALOME_Container``). - - -Eléments de conception -====================== - - -Implantation technique ----------------------- - -Le diagramme ci-dessous représente l'organisation des principaux -paquets logiciels du module MED: - -.. image:: images/medmem-layers.png - :align: center - -Les cadres bleus représentent le lieu d'implantation des -développements effectués dans le module MED pour les besoins du -maquettage. On notera en particulier les interventions aux niveaux -suivants: - -* interfaces idl: ajout de l'interface MEDOP.idl -* package MEDMEM_I: ajout du servant SALOME_MED::MEDOP qui implémente - l'interface MEDOP.idl - -Architecture technique ----------------------- - -Les schéma ci-dessous représente les objets informatiques qui sont à -l'oeuvre pour la réalisation des opérations sur les champs: - -.. image:: /images/xmed-architecture.png - :align: center - :alt: Objets mis en oeuvre dans l'interface de manipulation de champs - -On distingue les objets suivants: - -* Une instance de ``MEDMEM::MED``, correspondant à la structure de donnée - MED chargée en mémoire. -* Des instances de ``MEDMEM::FIELD`` qui représentent les champs med - chargés en mémoire. -* Une instances de ``SALOME_MED::MED`` et des instances de - ``SALOME_MED::FIELD`` qui sont les servants CORBA respectivement de la - structure med et des champs qui lui sont associés et chargés en - mémoire. -* Une instance de ``SALOME_MED::MEDOP`` qui est le servant CORBA qui - centralise la mise en oeuvre des opérations de champs sur le serveur - ``SALOME_Container``. Le servant MEDOP détient en attribut une référence - sur la structure ``MEDMEM::MED``, ce qui lui permet d'accéder - directement aux champs ``MEDMEM::FIELD`` à partir de leur nom et du pas - de temps. -* Des instances de ``FieldProxy`` qui correspondent aux variables - manipulées au niveau de l'interface graphique et qui représentent - les champs. Une instance de FieldProxy possède détient les - références des servants ``SALOME_MED::MEDOP`` et - ``SALOME_MED::FIELD`` sous la forme de pointeurs CORBA de noms - ``medop_ptr`` et ``field_ptr`` respectivement. -* Il existe également une instance de ``MedProxy`` non représentée - dans ce diagramme. Cette instance correspond à une variable qui - permet de manipuler la structure med. - -.. note:: Les éléments apportés par la maquette sont les classes - ``SALOME_MED::MEDOP``, ``MedProxy`` et ``FieldProxy``. Les autres - éléments ont pu être modifiés légèrement pour les besoins de - l'intégration ou pour la correction de quelques bugs. - -Le cycle de vie de ces objets est le suivant. - -Pour ce qui concerne les instances de la structure ``MEDMEM::MED`` et -des champs ``MEDMEM::FIELD``, la création est faite au moment du -chargement du fichier med dans SALOME au moyen du module MED. A cette -occasion, les servants CORBA associés ``SALOME_MED::MED`` et -``SALOME_MED::FIELD`` sont créés et des références vers ces servants -sont publiés dans l'étude. Ils peuvent donc être sélectionnés par -l'utilisateur dans l'interface graphique. L'ensemble de ces données -préexiste à la manipulation de champs. - -Les objets ``SALOME_MED::MEDOP`` sont instanciés au sein du servant -``SALOME_MED::MED`` auquel ils sont associées. Le servant -``SALOME_MED::MED`` possède une référence sur la structure -``MEDMEM::MED`` et il la transmet à l'instance du servant -``SALOME_MED::MEDOP`` qu'il construit. L'opérateur MEDOP est donc -autonome par la suite pour manipuler les données MED, et les champs en -particulier. Le code python ci-dessous montre comment un opérateur med -``SALOME_MED::MEDOP`` peut être créé puis utilisé pour réaliser -l'addition de deux champs: - -.. code-block:: python - - import salome - salome.salome_init() - import SALOME_MED - - medComp = salome.lcc.FindOrLoadComponent("FactoryServer", "MED") - medObj = medComp.readStructFile("myfile.med",salome.myStudyName) - medOp = medObj.createMedOperator() - - f1 = medObj.getField("testfield1",-1,-1) - f2 = medObj.getField("testfield2",-1,-1) - - somme = medOp.add(f1,f2) - -Il est à noter qu'une instance de ``SALOME_MED::MEDOP`` est associé à -une instance unique de ``SALOME_MED::MED`` (et donc indirectement de -``MEDMED::MED``) pour toute la durée de son cycle de vie. Par contre, -un servant ``SALOME_MED::MED`` peut être associé à plusieurs servants -``SALOME_MED::MEDOP`` différents. Un servant ``SALOME_MED::MEDOP`` a -une référence directe sur la structure ``MEDMEM::MED`` et peut la -manoeuvrer pour demander des champs, faire des opérations avec ces -champs, ajouter le champs résultat à la structure et enfin retourner -un servant ``SALOME_MED::FIELD`` qui encapsule le champ résultat. - -Enfin, quelques éléments concernant la classe ``FieldProxy``. Une -instance de ``FieldProxy`` est un objet python qui peut être -manoeuvrée dans l'interpréteur SALOME et qui référence un champ MED -localisé sur le serveur ``SALOME_Container`` (par le mécanisme décrit -ci-dessus). C'est à ce niveau qu'on règle les détails d'ergonomie -d'usage (cf. paragraphe ci-après). La création d'un objet -``FieldProxy`` déclenche la création d'un opérateur med (instance de -``SALOME_MED::MEDOP``) qui lui est associé et dont il conserve la -référence CORBA en attribut (noté ``medop_ptr`` sur le diagramme). Cet -opérateur ``medop_ptr`` peut être requêter pour exécuter toutes les -opérations possibles sur ce champ, comme illustrer sur l'exemple -ci-dessus. - - -Rôle des objets proxy ---------------------- - -Dans le modèle d'architecture présenté ci-dessus, on introduit deux -types d'objets proxy: - -* Les objets de classe ``FieldProxy`` qui représentent des poignées de - manipulation des champs ``MEDMEM::FIELD`` physiquement instanciés - dans le container SALOME. -* Les objets de classe ``MedProxy`` qui représentent des poignées de - manipulation des structures ``MEDMEM::MED`` physiquement instanciées - dans le container SALOME. - -Elles sont instanciées dans l'interpréteur python SALOME pour -manipulation dans l'interface textuelle à partir de la donnée du -pointeur vers le servant ``SALOME_MED::MED`` et de l'identifiant du -champ (le nom du champ et le pas de temps défini par le numéro d'ordre -et le numéro d'iteration: - -.. code-block:: python - - import salome - salome.salome_init() - import SALOME_MED - - medComp = salome.lcc.FindOrLoadComponent("FactoryServer", "MED") - medObj = medComp.readStructFile("myfile.med",salome.myStudyName) - - from xmed import fieldproxy - from xmed import medproxy - - f1 = fieldproxy.getFieldFromMed(medObj, "testfield1", -1, -1) - f2 = fieldproxy.getFieldFromMed(medObj, "testfield2", -1, -1) - - field_somme = f1 + f2 - field_offset = f1 + 5.3 - -Dans cet exemple, les variables ``f1``, ``f2``, ``field_somme`` et -``field_offset`` sont des objets de classe ``FieldProxy``. Ils -correspondent aux variables physiquement manipulées par -l'utilisateur pour désigner les champs dans les opérations. - -Ces classes proxy sont conçues pour être le lieu d'implémentation de -l'interprétation des commandes utilisateur et donc de l'ergonomie -de manipulation des champs au niveau l'interface textuelle. Ce point -est développé :ref:`plus bas `. - -Programmation de l'interface textuelle --------------------------------------- - -Dans le cadre de la maquette, l'interface de manipulation des champs -est l'interface textuelle python intégrée à SALOME. Dans la pratique, -l'utilisateur manipule des variables python qui correspondent à des -objets de classe ``FieldProxy`` équipées des fonctions requises et de -l'ergonomie nécessaire à la mise en oeuvre des opérations (voir -ci-dessus). - -Or, l'hypothèse de travail est que les données MED sont chargées dans -SALOME et publiées dans l'étude pour point d'accés depuis l'interface -graphique. L'utilisateur choisi un champs directement dans l'arbre -d'étude (ou dans une interface graphique dédiée) puis demande qu'il -soit mis à disposition dans l'interface python sous un nom de variable -à choisir. Les captures d'écran ci-dessous montre la séquence -graphique en images: - -.. |IMG_SELECT| image:: images/medop-gui-selectfield_scale.png -.. |IMG_ALIAS| image:: images/medop-gui-aliasfield_scale.png - -+---------------+---------------+ -| |IMG_SELECT| | |IMG_ALIAS| | -+---------------+---------------+ - -L'image de gauche montre la sélection du pas de temps, l'image de -droite la boîte de dialogue qui permet la saisie de l'alias avec -lequel le champs sera manipulé dans l'interface textuelle. La -validation de cette fenêtre doit mettre automatiquement le champ à -disposition dans l'interface python SALOME et sous le nom de variable -spécifié par l'alias saisi. - -Pour cela, il y a un couplage technique à programmer entre l'interface -graphique et l'interface textuelle python, avec en particulier la -transmission des pointeurs vers les servants CORBA mis en jeu dans la -sélection. - -Ce couplage est implanté au niveau de la classe MEDGUI.cxx du module -MED (où de la classe XMEDGUI.cxx du module XMED pour la maquette) qui -implémente l'interface graphique du module. Pour rappel, l'interface -graphique d'un module SALOME se présente sous la forme d'une classe -centrale de nom ``GUI`` et qui spécialise la classe -``SalomeApp_Module``. Cette classe possède une méthode ``getApp()`` -par laquelle on peut récupérer une instance de la console python -embarquée (this->getApp()->pythonConsole()). - -Le code suivant illustre l'envoie d'une commande python par ce -mécanisme. Dans cet example, on cherche à reconstituer dans le -contexte de la console python un pointer vers un objet med instancié -dans le contexte C++ de l'application graphique. Pour cela, on -communique la référence de l'objet sous la forme sérialisé (IOR pour -un objet CORBA): - -.. code-block:: cpp - - #include - #include - #include - #include - - // We suppose here that we have a CORBA object reference (object of - // type *_ptr or *_var), for example a SALOME_MED::MED object. - SALOME_MED::MED_ptr medObj = ... // anything to get this object - - // Get the IOR of this object - QString medIOR = SalomeApp_Application::orb()->object_to_string(medObj); - - PyConsole_Console * pyConsole = getApp()->pythonConsole(); - - QStringList commands; - commands+="import salome"; - commands+=QString("med=salome.orb.string_to_object(\"%1\")").arg(medIOR); - - QStringListIterator it(commands); - while (it.hasNext()) { - pyConsole->exec(it.next()); - } - -Le code réel de la maquette est basé sur ce principe et transmet à la -console python des lignes de commandes qui permettent de reconstruire: - -* un pointeur CORBA vers le servant ``SALOME_MED::MED`` associé au - champ sélectionné; -* une instance de ``FieldProxy`` qui correspond au champ sélectionné - et avec pour nom de variable la valeur de l'alias saisi dans - l'interface graphique. - -Au niveau du code C++ de la classe ``XMEDGUI.cxx``, cela se traduit -par la fabrication de la liste de commandes suivante pour envoie à la -console python par le mécanisme illustré plus haut: - -.. code-block:: cpp - - QStringList commands; - commands+="from xmed.fieldproxy import getFieldFromMed"; - commands+="from xmed.medproxy import getMedProxy"; - commands+=QString("if not dir().__contains__('med'): med = getMedProxy(\"%1\")").arg(medIOR); - commands+=QString("%1=getFieldFromMed(med,\"%3\",%4,%5)").arg(*alias).arg(fieldName).arg(orderIndex).arg(iterationIndex); - -Les variables ``medIOR``, ``fieldName``, ``orderIndex`` et -``iterationIndex`` sont construites à partir du champ sélectionné par -des techniques de programmation standard dans SALOME qu'on peut -examiner en détail dans la classe ``XMEDGUI`` (voir méthode -``XMEDGUI::LoadIntoPythonConsole()``). La variable ``alias`` est la -chaîne saisie par l'utilisateur dans la fenêtre de dialogue. - -Le point important à noter ici est que les données à transmettre -doivent être fournies sous forme de chaînes de caractères ou de types -simples. C'est pourquoi la référence au servant CORBA -``SALOME_MED::MED`` est transmise ici sous la forme de son IOR, -c'est-à-dire une chaîne de caractères qui permet l'identification de -l'objet au niveau du bus CORBA. - -Au niveau de la console python cela correspond à l'exécution des -commandes suivantes: - -.. code-block:: python - - from xmed.fieldproxy import getFieldFromMed - from xmed.medproxy import getMedProxy - - med = getMedProxy("IOR:010000001700000049444c3a53414c4f4d455f4d45442f4d45443a312e300000010000000000000064000000010102000e0000003133302e39382e37372e313733009e0a0e000000feadc4ca4c00003169000000001100000200000000000000080000000100000000545441010000001c00000001000000010001000100000001000105090101000100000009010100") - - f1=getFieldFromMed(med,"testfield1",-1,-1) - -Ce jeu d'instructions reconstitue un pointeur vers le servant CORBA -``SALOME_MED::MED`` à partir de son identifiant IOR (voir la fonction -``getMedProxy(...)``, puis crée une instance de ``FieldProxy`` -associée à ce servant (en fait associée au servant -``SALOME_MED::MEDOP`` créé sur demande par le servant -``SALOME_MED::MED``, voir la fonction ``getFieldFromMed(...)``). - -.. _develguide_execFieldOperation: - -Exécution des opérations sur le champs --------------------------------------- - -Les variables définies dans l'interface textuelle pour désigner les -champs à manipuler sont des objets de classe ``FieldProxy``. - -Cette classe a une propriété remarquable, elle est construite sur un -design pattern de type "Proxy" qui pointe vers un servant -``SALOME_MED::FIELD``. Cela signifie que l'on ne peut pas accéder -directement au servant vers lequel il pointe, mais que l'on passe -systématiquement par une procédure de l'objet proxy qui fait "boîte -aux lettres": - -.. code-block:: python - - class FieldProxy: - - def __getattr__( self, name ): - """ - This method realizes the proxy pattern toward the servant - SALOME_MED::FIELD. - """ - return getattr( self.__field_ptr, name ) - -Ce pattern permet l'implémentation de pré-traitement et/ou de -post-traitement suivant le type d'accés que l'on cherche à faire. - -Il permet aussi et surtout de fournir un objet python qui présente -l'interface de ``SALOME_MED::FIELD`` dotée d'extentions adhoc pour les -operations de champs. Ici, python est ton ami, car il s'agit pour cela -d'équiper la classe ``FieldProxy`` des automatismes prévus nativement -par python pour les operations entre objets. En particulier, la -re-définition des fonctions internes ``__add__`` (opérateur addition), -``__sub__`` (opérateur soustraction), ``__mul__`` (opérateur -multiplication) et ``__div__`` (opérateur division) au sein de la -classe ``FieldProxy``, permet de prendre la main sur le comportement -des opérations algébriques et de définir une ergonomie sur mesure. Par -exemple, la méthode ``__add__`` peut gérer les variantes "f1+f2" -(ajout de deux variables de type FieldProxy) et "f1+5.3" (ajout d'un -réel à une variable de type FieldProxy): - -.. code-block:: python - - class FieldProxy: - - def __add__(self, operande): - """ - This can process the addition of two fields or the addition of - a scalar to a field. It depends weither the operande is a - FieldProxy or a simple scalar numerical value. - """ - if isinstance(operande, FieldProxy): - # The operande is an other field - otherField_ptr = operande.__field_ptr - rfield_ptr = self.__medOp_ptr.add(self.__field_ptr, otherField_ptr) - else: - # The operande is a scalar numerical value that must be - # considered as an offset in a linear transformation - factor = 1 - offset = operande - rfield_ptr = self.__medOp_ptr.lin(self.__field_ptr, factor, offset) - return FieldProxy(self.__med_ptr, rfield_ptr) - -Il est à noter que dans les deux cas de figure (opérande=champ ou -opérande=scalaire), la fonction délègue la réalisation concrète de -l'opération au servant ``SALOME_MED::MEDOP`` (identifié ici par -l'attribut ``self.__medOp_ptr`` et que l'on appelera l'*opérateur -MEDOP* dans la suite pour simplifier), mais n'appelle pas le même -service de calcul (l'addition entre champs dans le premier cas, -l'application d'une transformation linéaire de type y=factor*x+offset -dans le deuxième cas). - -Pour couvrir le cas des opérations algébriques, l'opérateur MEDOP -présentre l'interface suivante (cf. fichier ``MEDOP.idl`` qui définie -l'interface du servant ``SALOME_MED_MEDOP``): - -.. code-block:: cpp - - /*! Addition of the fields f1 and f2 ( f1+f2) */ - FIELD add(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception); - /*! Substraction of the fields f1 and f2 (f1-f2) */ - FIELD sub(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception); - /*! Multiplication of the fields f1 by f2 (f1*f2) */ - FIELD mul(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception); - /*! Division of the fields f1 by f2 (f1/f2) */ - FIELD div(in FIELD f1, in FIELD f2) raises (SALOME::SALOME_Exception); - /*! Power of the field f (f^power) */ - FIELD pow(in FIELD f, in long power) raises (SALOME::SALOME_Exception); - /*! Linear transformation of the field f (factor*f+offset) */ - FIELD lin(in FIELD f, in double factor, in double offset) raises (SALOME::SALOME_Exception); - /*! Dublication of the field f */ - FIELD dup(in FIELD f) raises (SALOME::SALOME_Exception); - -Cette interface est implémentée dans la classe C++ ``MEDOP_i`` du -module MED (voir fichier ``MEDMEM_MedOp_i.hxx`` du package -``MEDMEM_I``). C'est au sein des instances de cette classe que sont -réalisées les opérations et que sont produites physiquement les -données. Typiquement, les opérations présentées ici produisent un -champ ``MEDMEM::FIELD`` sur la base duquel elle fabrique un servant -``SALOME_MED::FIELD`` pour finalement retourner un pointeur CORBA sur -ce servant. - -Ce mécanisme global peut être étendu sans limitation à tout les types -d'opération qui sont envisagés dans les spécifications de manipulation -des champs dans SALOME. - - -Contrôle visuel des champs --------------------------- - -Les illustrations ci-dessous montrent qu'une fonction de visalisation -est implémentée dans la maquette pour permettre le contrôle visuel -d'un champ au moyen d'une représentation 3D (une carte spatiale du -module du champ dans l'exemple implémenté par défaut): - -.. |IMG_VISU| image:: images/medop-gui-visufield_scale.png -.. |IMG_RESULT| image:: images/medop-gui-result_scale.png - -+---------------+---------------+ -| |IMG_VISU| | |IMG_RESULT| | -+---------------+---------------+ - -Cette fonction répond au besoin de contrôle interactif des résultats -produits par les opérations de manipulation de champs. - -Il s'agit là d'un usage classique de SALOME, dans lequel on demande au -module VISU de faire une représentation 3D d'un champ spécifié par la -donnée du servant ``SALOME_MED::FIELD`` qui lui est associé -(représenté par la variable ``field_ptr`` dans l'exemple ci-dessous): - -.. code-block:: python - - import salome - import VISU - - visuComp = salome.lcc.FindOrLoadComponent("FactoryServer", "VISU") - visuComp.SetCurrentStudy(salome.myStudy) - - # Then we can import the specified field in the VISU module. This - # creates an study entry in the VISU folder. - result = visuComp.ImportMedField(field_ptr) - - meshName = field_ptr.getSupport().getMesh().getName() - fieldName = field_ptr.getName() - iterNumber = field_ptr.getIterationNumber() - scalarmap = visuComp.ScalarMapOnField(result, - meshName, - visuEntityType, - fieldName, - iterNumber) - -Dans ce jeu d'instructions donné pour exemple (non fonctionnel, en -particulier à cause de la non définition de la variable -``visuEntityType``, voir remarque plus bas), le composant VISU -désigné ici par la variable ``visuComp`` va chercher les données du -champ en interrogeant le servant ``SALOME_MED::FIELD`` transmis en -argument de la fonction ``ImportMedField``, puis produit une -représentation de type "scalarmap". - -.. note:: Compte-tenu des propriétés de la classe FieldProxy décrites - plus haut conférées par le pattern "Proxy", on peut transmettre ici - aussi bien le servant CORBA que l'instance du proxy (la fonction - ``ImportMedField`` n'y verra que du feu). - -Le code complet et fonctionnel de la fonction d'affichage est dans le -corps du module python ``fieldproxy.py`` sous la forme d'une fonction -de nom ``visuField``. Il convient de noter que cette fonction doit -établir une correspondance entre le type des entités tel que défini -dans MED et dans VISU: - -.. code-block:: python - - medEntityType = field_ptr.getSupport().getEntity() - if (medEntityType == SALOME_MED.MED_CELL): - visuEntityType = VISU.CELL - elif (medEntityType == SALOME_MED.MED_NODE): - visuEntityType = VISU.NODE - - -Export des résultats de calcul ------------------------------- - -Tous les champs produits à l'occasion des opérations entre objets -``FieldProxy`` sont automatiquement ajoutés à la structure med à -laquelle is sont associés. Une convention d'attribution des noms est -implémentée de sorte que par défaut aucune précision n'est demandée à -l'utilisateur. - -La structure med peut être manipulée au moyen de la variable ``med`` -créée dans l'interface textuelle comme une instance de la classe -``MedProxy``. La classe ``MedProxy`` fournit un objet qui présente -l'interface du servant ``SALOME_MED::MED`` étendue de quelques -fonctions utilitaires pour la gestion et le contrôle des données. - -En particulier, la sauvegarde de la structure dans un fichier est -automatisée par la méthode ``save(medfilename)``: - -.. code-block:: python - - med = medproxy.MedProxy(medObj) - med.save("/tmp/output.med") - -Cette méthode s'occupe de définir un driver d'écriture et de procéder -à l'enregistrement des données de la structure med (les maillages, les -champs présents au départ et tous les champs produits depuis la -lecture initiale). - -Limitations -=========== - -L'implémentation de la maquette limite l'usage des opérations aux cas -de figure suivants: - -* Seules les operations entre champs qui partagent le même support med - sont possibles. Ceci est une contrainte imposé par la conception - actuelle de MEDMEM. -* Le résultat d'une opérations est calculé sur toutes les composantes - et tout le domaine de définition des champs en opérande. Cette - deuxième contrainte est juste parce que les usages plus fin, - notemment avec la notion de domaine de définition, n'a pas encore - été exéminée à ce jour. -* Le nom d'un champ produit par une opération ne correspond pas au nom - de la variable python par laquelle on le réceptionne et on le - manipule. Le nom est attribué par une convention (ceci n'est pas - vraiment une limitation mais une caractéristique à connaître). - -On note également les restriction techniques suivantes: - -* Les données MEDMEM sont supposées être chargées par le composant MED - puis référencées dans l'étude SALOME (comme c'est fait aujourd'hui - par le module MED). -* Dans certain cas, python n'est pas ton ami. Pour que les opérateur - de la classe ``FieldProxy`` soient pris en considération dans les - opérations sur les champs, il est indispensable que le premier - opérande d'une opération unitaire soit un champ (objet de classe - ``FieldProxy``). Par exemple: "field_offset = field + 5.3" - fonctionne alors que "field_offset = 5.3 + field" ne fonctionne pas - car python tente de traiter la situation au moyen de la fonction - ``__add__`` de la classe ``float`` (qui n'est pas modifiable). - - -Notice informatique -=================== - -Gestion de configuration ------------------------- - -Les développements décrits dans ce chapitre sont répartis entre les -modules MED et XMED (développé pour l'occasion). Cette séparation est -faite par soucis de clarté et d'efficacité de développement, mais les -éléménts du module XMED ont vocation à intégrer le module MED dans la -mesure où les propositions techniques sont retenues pour le -développement à venir. - -Le code source du module XMED peut être récupérés par la commande -suivante:: - - $ svn co svn://nepal.der.edf.fr/FIELD/XMED_SRC/trunk XMED_SRC - -Le pré-requis est la plate-forme SALOME version 5.1.4 (ou plus) -équipée au minimum des modules KERNEL, GUI, MED (branche BR_medop) et -VISU. Pour récupérer la branche BR_medop du module MED, taper la -commande:: - - $ cvs -d :pserver:anonymous@cvs.opencascade.com:2401/home/server/cvs/MED co -r BR_medop MED_SRC - -La configuration de référence est: - -* XMED: révision svn 41 -* MED: tag cvs BR_medop_20101025 - -Moyens de tests ---------------- - -Plusieurs types de tests unitaires sont définis (reste à les -automatiser proprement): - -* Test des servants et utilitaires de manipulation python: - - - Dans XMED, package xmed/tests, utiliser le script - ``test_medoperation.py`` dans un interpréteur python lancé dans - une session shell SALOME. Ce script prépare des variables de test - et fournit des fonctions de test unitaire (à exécuter ou pour s'en - inspirer). Après avoir lancé SALOME via une application virtuelle, - on peut taper:: - - $ /runSession - [NS=venus:2810] $ python -i test_medoperation.py - >>> - - - Ceci permet de tester en particulier l'interface ``MedOp`` et son - utilisation dans le module python ``fieldproxy.py``. - -* Test des classes MEDMEM: - - - Test de MEDMEM::MedDataManager dans ``MEDMEM_MedDataManager_test.cxx`` - -Un fichier de test basique (mais néanmoins suffisant) de nom -``tesfield.med`` est fourni avec les sources dans le répertoire -``/resources/datafiles`` et dans l'installation au niveau du -répertoire ``/share/salome/resources/xmed/datadir``. Il -contient deux champs ``testfield1`` et ``testfield2`` définis sur un -pas de temps unique (dt,it=-1,-1). Ces champs définissent des valeurs -par éléments (MED_CELL). diff --git a/src/MEDOP/doc/sphinx/xmed-prototype-medmem.rst b/src/MEDOP/doc/sphinx/xmed-prototype-medmem.rst deleted file mode 100644 index da331c05e..000000000 --- a/src/MEDOP/doc/sphinx/xmed-prototype-medmem.rst +++ /dev/null @@ -1,513 +0,0 @@ -.. meta:: - :keywords: maillage, champ, MED, MEDMEM - :author: Guillaume Boulant - -.. include:: xmed-definitions.rst - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Note de travail concernant l'utilisation de MEDMEM -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -Le module MED de SALOME comporte plusieurs composants d'intérêt pour -la manipulation de champs: - -* la bibliothèque MEDMEM qui fournit une interface de programmation - pour manoeuvrer une structure MED -* le module CORBA SALOME_MED qui matérialise le composant SALOME - (serveur corba) du module MED -* l'interopérabilité avec le module VISU qui permet la visualisation - des champs manipulés dans MED - -Les sections ci-après donnent quelques éclairages techniques sur ces -différents aspects. Les sources de démonstration peuvent être -récupérés depuis le dépôt svn:: - - $ svn export svn://nepal.der.edf.fr/OM/manifield/trunk manifield - $ svn export svn://nepal.der.edf.fr/FIELD/demofield/trunk demofield - -.. contents:: Sommaire - :local: - :backlinks: none - -Présentation synthétique de MED -=============================== - -MED désigne un modèle conceptuel pour décrire des données de type -éléments finis (éléments finis, volumes finis et éléments -discrets). Dans l'usage courant, il permet la description et l'échange -des données de calcul de type maillages et champs. La documentation -complète peut être trouvée à l'URL suivantes: - -* |LINK_EDF_MEDDOC|_ (version 2.3). - -On distingue deux implémentations informatiques de ce modèle: - -* MED fichier: qui permet la lecture et l'écriture de données depuis - un fichier au format med. Les opérations de lecture/écriture sont - atomiques (pas de chargement de la structure de données globale). -* MED mémoire (noté MEDMEM): qui permet le chargement en mémoire d'une - image de la structure de données MED contenue dans un fichier au - format med. Les opérations peuvent être atomiques ou - globales. - -On notera simplement ici que MEDMEM utilise MED fichier pour les -opérations de lecture/écriture et que MED fichier est indépendant de -MED mémoire. La documentation complète de MED fichier peut être -trouvée à l'URL suivante: - -* |LINK_EDF_MEDFICHIERDOC|_ - -La bibliothèque MEDMEM -====================== - -Le modèle de classes MEDMEM est structuré autour des notions de MESH -(les maillages), de SUPPORT (le profil des entités) et de FIELD (les -champs). Ces notions reprennent en partie des concepts du modèle -MED. Le diagramme ci-dessous présente les classes principales: - -.. image:: images/med-uml-main_60pc.png - :align: center - -Le conteneur de plus haut niveau dans MEDMEM est la classe MED. La -figure ci-dessous indique qu'une instance MED peut être associée à -plusieurs maillage et plusieurs champs. Par contre un champ donné ne -peut être associé qu'à un seul maillage (par l'intermédiaire du -support). Plusieurs champs peuvent être associés au même maillage. La -forme la plus courante est d'ailleurs une instance composé d'un -maillage unique sur lequel sont définis plusieurs champs. - -On peut avoir également des configurations plus complexes, comme par -exemple un maillage unique, plusieurs champs définis sur ce maillage -mais avec des supports différents, par exemple parce que les valeurs -sont définies sur des entités de maillage différentes (les éléments -pour un champ, les noeuds pour un autre, ...):: - - field1->support1->mesh - field2->support2->mesh - field3->support3->mesh - -On observe: - -* 2 champs U et V doivent avoir le même support (au sens informatique - du terme) pour pouvoir être en argument d'une opération (sinon - exception). Il faudrait accepter qu'il soit informatiquement - différent et vérifier la conformité conceptuelle. -* Cette contrainte peut se comprendre car physiquement les données - sont stockées dans un vecteur qui couvre toutes les mailles. Le - support est le seul masque de lecture pour établir la correspondance - avec les positions dans le maillage et il est donc important qu'une - cohérence soit assurée. - -Les objets champs (FIELD) et maillage (MESH) --------------------------------------------- - -Un objet MED permet d'accéder aux différentes informations concernant -les objets MESH, SUPPORT et FIELD, mais il ne permet pas d'accéder aux -données physiques associées à ces objets (les valeurs des composantes -pour les champs, les mailles et leur connectivité pour les -maillages). L'accès aux données physiques est du ressort des objets -spécifiques MESH, SUPPORT et FIELD. - -Un objet MED peut être créé intégralement en mémoire. L'usage plus -fréquent est de l'initialiser à partir de la donnée d'un fichier -med. Pour cela, l'objet MED doit être associé à un driver -d'entrée/sortie branché sur le fichier (``testfilename`` dans -l'exemple): - -.. code-block:: cpp - - MED *myMed = new MED; - MED_MED_RDONLY_DRIVER *driverIn = new MED_MED_RDONLY_DRIVER(testfilename, myMed); - driverIn->open(); - driverIn->readFileStruct(); - driverIn->close(); - -A l'occasion de la fonction readFileStruct, la structure interne de -l'objet MED est enrichie des informations concernant les objets MESH, -SUPPORT et FIELD contenu dans le fichier. En particulier un -dictionnaire des champs (variable map interne) est initialisé est -contient l'ensemble des objets ``FIELD_`` préchargés (i.e. avec les -méta-données uniquement). Chaque objet ``FIELD_`` ainsi préchargé est -autonome pour être chargé sur demande. On peut alors requêter l'objet -MED pour obtenir un champ particulier (spécifié par son nom -``fieldname`` dans l'exemple): - -.. code-block:: cpp - - FIELD *field = (FIELD *)myMed->getField(fieldname, dt, it); - -Puis le champ qui lui est associé doit être physiquement chargé pour -permettre la mise à jour du support: - -.. code-block:: cpp - - MESH * mesh = myMed->getMesh(field); - mesh->read(); - myMed->updateSupport(); - -Pour enfin charger les valeurs des composantes du champ: - -.. code-block:: cpp - - field->read(); - -La numérotation des éléments de maillage ----------------------------------------- - -Les éléments qui composent un maillage sont caractérisés par: - -* Le type d'entité de l'élément, à choisir dans la liste - ``MED_EN::medEntityMesh``, qui contient en particulier ``MED_NODE``, - ``MED_FACE``, ``MED_CELL``. -* Le type de géométrie de l'élément, à choisir dans la liste - ``MED_EN::medGeometryElement``, qui contient en particulier - ``MED_NONE``, ``MED_TRIA3``, ..., ``MED_ALL_ELEMENTS``. - -Les éléments sont numérotés par un indice relatif à la catégorie -géométrique à laquelle ils appartiennent. Ainsi, si le modèle est -composé de Na arrêtes et Nf faces de type géométrique MED_QUAD4, alors -ces faces sont numérotées de 1 à Nf dans le modèle MED (et de manière -persistente dans le fichier med). De même, les arrêtes sont numérotées -de 1 à Na. Une numérotion globale implicite existe sur les éléments, -elle consiste à parcourir l'ensemble des types géométriques dans -l'ordre de définition du modèle de données. Ainsi, si le modèle -contient uniquement les Na arrêtes et les Nf faces, alors l'indice -global de la première face est Na+1. - -.. note:: Des exemples de code sont disponibles dans le package ``demofield``, fichier ``python/pybasicfields/MEDMEM_tester.py``. - - -Binding python de MEDMEM ------------------------- - -Les classes du package ``MEDMEM`` (package du module ``MED`` qui -implémentent les structures de données C++ de MED mémoire) produisent -la bibliothèque ``libmedmem.so``. Cette ensemble de classes est en -partie mis à disposition de l'interface python grace à une couche de -liaison (binding Python-C++) générée par le logiciel SWIG à partir -d'un fichier de description d'interface ``libMEDMEM_Swig.i`` (dans le -package source ``MEDMEM_SWIG``). - -Ce fichier d'interface doit être mis à jour dés lors qu'une évolution -des interfaces publiques des classes C++ MEDMEM est faite ou qu'une -nouvelle classe est créée (du moins si l'on souhaite profiter de ces -évolutions dans l'interface python). - -Cette mise à jour nécessite de prendre soin au transfert des -structures de données entre les espaces python et C++. En particulier, -l'utilisation des template de classe pour décrire les champs typés en -C++ appelle une précaution de codage particulière de l'interface -SWIG. - -Pour exemple, le fragment de code ci-dessous, extrait du fichier -``libMEDMEM_Swig.i``, montre comment déclarer la nouvelle classe -``MedDataManager`` dans l'interface: - -.. code-block:: cpp - - #include "MEDMEM_MedDataManager.hxx" - - class MedDataManager - { - public: - ~MedDataManager(); - void printFieldDouble(FIELD * field); - - %extend { - MedDataManager(char * fileName) - { - return new MedDataManager(string(fileName)); - } - MedDataManager(MED * med) - { - return new MedDataManager(med); - } - - %newobject getFieldDouble(const char * fieldName, const int dt, const int it); - FIELD * getFieldDouble(const char * fieldName, const int dt, const int it) - { - return (FIELD *) self->getFieldDouble(string(fieldName), dt, it); - } - } - - }; - - -Utilisation de MEDMEM pour la manipulation de champs ----------------------------------------------------- - -Des opérations de manipulation de champs sont disponibles dans la -bibliothèque MEDMEM standard est peuvent être utilisées dans -l'interface python. Les quelques lignes suivantes illustrent l'usage -qu'on peut en faire pour exécuter l'addition de deux champs sur tout -leur espace de définition et pour un pas de temps donné: - -.. code-block:: python - - from libMEDMEM_Swig import MedDataManager - from xmed.helper import readMed, writeMed - - # Load the medmem data structure from a med file - med = readMed("/tmp/input.med") - # Then create a med data manager to deal with the fields data - dm = MedDataManager(med) - # Get the timestamps (dt,it)=(-1,-1) of the fields "testfield1" and "testfield2" - f1 = dm.getFieldDouble("testfield1",-1,-1) - f2 = dm.getFieldDouble("testfield2",-1,-1) - - # Create a new field as the sum of f1 and f2 - r = f1 + f2 - # And add this new field to the med data structure - med.addField(r) - - # Finally, write the whole data in an output med file - writeMed(med,"/tmp/output.med") - -.. note:: Cet exemple de code requiert les évolutions de MEDMEM - opérées dans la branche BR_medop (pour disposer de la classe - MedDataManager en particulier) et le package python ``xmed`` qui - fournit quelques fonctions utilitaires pour manoeuvrer les données - med (ce package est dans le module XMED et sera probablement à - terme intégré au module MED). - -Des limitations existent aujourd'hui pour ce type de manipulations: - -* les champs doivent partager le même support MED, c'est-à-dire être - décrit sur le même maillage et sur les mêmes entités de ce - maillage. -* ... - - -Remarque sur l'implémentation C++ ---------------------------------- - -A noter l'usage de plusieurs formes d'arguments pour les fonctions: - -* passage des arguments par valeur ``myfunction(A a);`` -* passage des arguments par référence ``myfunction(A& a);`` -* passage des arguments par pointeur ``myfunction(A* a);`` - -Le passage des arguments par référence est une facilité d'écriture -pour éviter de passer un pointeur tout en évitant la récopie des -données de la variable. - -.. _xmed-medmem_corbainterface: - -L'interface CORBA SALOME_MED -============================ - -Implémentation du composant MED et des servants SALOME_MED::\* --------------------------------------------------------------- - -Le composant MED est un servant CORBA qui permet la manipulation de -données MEDMEM dans l'environnement SALOME. Le composant peut fournir -des pointeurs vers des instances de l'interface SALOME_MED (objets -SALOMEMED::MED, SALOME_MED_FIELD, ...). Ces instances sont des -servants CORBA qui résident dans le container et qui encapsulent les -données MEDMEM. - -Le schéma ci-dessous représente les éléments informatiques qui -composent l'architecture CORBA du module MED: - -.. image:: images/medmem-corba-layers.png - :align: center - -Les structures MEDMEM (données physiques) et SALOME_MED (wrapping -CORBA) fonctionnent différement en ce qui concerne le chargement des -données: - -* Dans MEDMEM, les données sont chargées à la demande (fonctions read - des objets) et aucune gestion n'est assurée. En particulier l'appel - à read alors que la donnée est déjà chargée conduit à une levée - d'exception. C'est à l'utilisateur de MEDMEM de prendre en charge ce - type de gestion. -* Dans SALOME_MED, les données sont chargées à la création de - l'instance SALOME_MED::MED. Les maillages ainsi que les champs et - leurs données sont chargés à ce moment là et gérés dans une table de - type HashMap au niveau de la structure SALOME_MED::MED. Cette - structure remplie dés lors des fonction de gestion. L'appel à - SALOME_MED::MED.getField(...) ne charge pas les données mais renvoie - un pointeur SALOME_MED::FIELD_ptr sur les données chargées à - l'initialisation (ATTENTION, cette fonction est bugguée dans la - branche principale -> Fix dans la branche BR_medop). - -Une gestion intermédiaire peut être envisagée: le chargement à la -demande géré dans une ou plusieurs tables de champs (une pour chaque -type de valeur numérique). Une implémentation de ce type de gestion -est illustré dans la classe ``MedDataManager`` du package MEDMEM qui prend -en charge ce comportement pour les structures de données MED (en -particulier les champs). - -Utilisation du composant MED ----------------------------- -Le module SALOME MED fournit un module CORBA appelé SALOME_MED. Les -interfaces de ce module CORBA sont spécifiées par les fichiers idl -suivants: - -* le fichier - [http://nepal.der.edf.fr/pub/SALOME_userguide/MED5/doc/salome/tui/MED/MED_8idl.html - ``MED.idl``] qui décrit les interfaces des objets manipulés par le - module SALOME_MED. On trouve en particulier les objets MESH, SUPPORT - et FIELD. -* le fichier - [http://nepal.der.edf.fr/pub/SALOME_userguide/MED5/doc/salome/tui/MED/MED__Gen_8idl.html - ``MED_Gen.idl``] qui décrit les interfaces du composant SALOME - (c'est-à-dire le composant chargé par la commande - ``FindOrLoadComponent("FactoryServer", "MED")`` du - lyfeCycleCorba). On trouve: - - - l'interface ``MED_Gen_Driver`` qui hérite de SALOMEDS::Driver - pour l'implémentation des services généraux des composants SALOME - (persistance hdf, dump) - - l'interface ``MED_Gen`` qui hérite des interfaces - ``Engines::Component`` et ``MED_Gen_Driver`` pour - l'implémentation des services spécifiques du composant MED. - -L'implémentation de ces interfaces est faites au niveau de différents -packages des sources du module MED: - -* Le package ``MEDMEM_I`` qui fournit l'implémentation C++ des - interfaces décrites par le fichier ``MED.idl``; -* Le package ``MED`` qui fournit l'implémentation C++ des interfaces - décrites par le fichier ``MED_Gen.idl``, et qui correspond à la - partie composant classique d'un module SALOME. -* Le package ``MedCorba_Swig`` qui fournit une interface swig - générée à partir de l'implémentation C++ de ``MEDMEM_I`` et - ``MED`` - -L'utilisation peut être illustrée au moyen d'exemples python (i.e. qui -utilise l'interface swig fournie par MedCorba_Swig). Après l'import -d'amorce systématique: - -.. code-block:: python - - import salome - salome.salome_init() - - import SALOME_MED - from libSALOME_Swig import * - -On peut charger le composant SALOME MED: - -.. code-block:: python - - medComp=salome.lcc.FindOrLoadComponent("FactoryServer", "MED") - -grâce auquel les services de chargement de la structure MED peuvent -être invoqués. Par exemple, les commandes suivantes chargent toute la -structure MED dans l'étude salome passée en argument: - -.. code-block:: python - - filePathName = "myfile.med" - medComp.readStructFileWithFieldType(filePathName,salome.myStudyName) - -Ce deuxième exemple charge la structure MED mais ne place pas le résultat dans l'étude: - -.. code-block:: python - - filePathName = "myfile.med" - medObj = medComp.readStructFile(filePathName,salome.myStudyName) - -On récupère à la place un objet de classe |LINK_EDF_SALOME_MED__MED|_ -qui permet une utilisation assez semblable (mais différente on le -verra plus bas) à MEDMEM: - -.. code-block:: python - - fieldIdx = 1 # WRN maybe there is no field of idx=1 - iterationIdx = 0 - fieldName = medObj.getFieldNames()[fieldIdx] - dtitfield = medObj.getFieldIteration(fieldName,iterationIdx) - it = dtitfield[0] - dt = dtitfield[1] - fieldObj = medObj.getField(fieldName,it,dt) - nbOfFields = medObj.getNumberOfFields() - fieldNames = medObj.getFieldNames() - - mesh = fieldObj.getSupport().getMesh() - -.. note:: - Observations en vrac: - - * Un FIELD_i possède un champ de type ``MEDMEM::FIELD_`` qui représente - le champ informatique réel (objet MEDMEM). - * FIELD_i::fieldMap variable static de type map qui semble gérer - les différentes instances de FIELD_i (~pattern factory). Cette - map peut être requétée au moyen d'un indice de type long appelé - corbaIndex. - * Quand on crée un FIELD_i par le constructeur d'argument - ``MEDMEM::FIELD_``, le ``MEDMEM::FIELD_`` est ajouté dans la map avec - incrément du corbaIndex - * La fonction FIELD_i::read(i) redirige vers la fonction read(i) du - ``MEDMEM::FIELD_`` associé - * A CONFIRMER: Il semble que les fonctions de chargement - ``readStructFile*()`` charge toutes les données du fichier med, - alors qu'en MEDMEM seules les meta-données sont chargées. - * A CONFIRMER: il semble que le chargement d'une structure MED - CORBA peut se faire sans passer par le composant (cf. l'interface - de MED) - -Interface avec le module VISU -============================= - -Des interactions sont possibles entre MED et VISU à partir du moment -où les données med sont gérées dans l'étude, c'est-à-dire sous la -forme d'objets SALOME_MED (voir ci-dessus) publiés dans l'étude. Les -deux conditions sont aujourd'hui nécessaires (objet corba + publié -dans l'étude) mais il semble que ce ne soit lié qu'à un choix -d'interface VISU (la fonction ``ImportMed`` en particulier) qui peut -a priori être modifié. A CONFIRMER. - -L'exemple de code ci-dessous (en python, mais il peut être transposé à -une implémentation C++) montre par exemple comment envoyer au module -VISU une requête de visualisation d'un champs hébergé par le module -MED (en fait, les données sont gérées au travers d'un objet corba -SALOME_MED "délocalisé" et qui a été référencé dans l'étude dans la -catégorie du composant MED). Les importations standard (salome, -SALOME_MED, ...) sont supposées avoir été faites au préalable (voir -les exemples précédents): - -.. code-block:: python - - # Load the med structure using MED - medComp=salome.lcc.FindOrLoadComponent("FactoryServer", "MED") - filePathName = "myfile.med" - medComp.readStructFileWithFieldType(filePathName,salome.myStudyName) - - # Get the VISU component - import VISU - visuComp = salome.lcc.FindOrLoadComponent("FactoryServer", "VISU") - visuComp.SetCurrentStudy(salome.myStudy) - - # Get the sobject associated to the med object named "Med" - aSObject = salome.myStudy.FindObject("Med") - isPresent, medSObj = aSObject.FindSubObject(1) - - # Finally, import the med sobject in VISU - result = visuComp.ImportMed(medSObj) - -Il est possible de d'aller plus loin et par exemple de déclencher -l'affichage d'une scalarmap d'un champ spécifique pour une itération -particulière (voir la fonction -``TEST_SALOMEMED_requestToVisu_scalarmap`` du fichier -``SALOMEMED_tester.py`` fourni dans les sources d'exemple). - -Liens complémentaires: - -* http://nepal.der.edf.fr/pub/SALOME_userguide/VISU_V5_1_3/doc/salome/gui/VISU La documentation utilisateur en ligne du module VISU - - -Notes en vrac -============= - -Questions: - -* Comment obtenir le nom du fichier med à partir d'une structure med? -* Peut-on imaginer un moyen de fournir l'objet MEDMEM::MED à partir de - la donnée de l'objet CORBA SALOME_MED::MED? - -Remarques: - -* A part, les opérations arithmétiques (+,-,*,/), aucune opération - n'est définie. diff --git a/src/MEDOP/doc/sphinx/xmed-prototype-overview.rst b/src/MEDOP/doc/sphinx/xmed-prototype-overview.rst deleted file mode 100644 index c571c6e6f..000000000 --- a/src/MEDOP/doc/sphinx/xmed-prototype-overview.rst +++ /dev/null @@ -1,95 +0,0 @@ -.. meta:: - :keywords: maillage, champ, manipulation, XMED - :author: Guillaume Boulant - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Démonstrateur XMED, vue d'ensemble -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -Le module XMED est un espace d'expérimentation pour le développement -des opérations de manipulation de champs. Il complète des -développements intégrés directement dans le module MED et gérés dans -la branche CVS BR_medop. - -Une maquette est au point pour illustrer les propositions en matière -d'ergonomie d'utilisation et en matière d'architecture technique. La -maquette permet de réaliser des cas d'utilisation de la forme: - -* Chargement d'un fichier med dans le module MED (ou publication par - un code de calcul). -* Sélection graphique des champs de l'étude à mettre à disposition - dans la console utilisateur ("calculette" en mode texte qui - concraitement correspond à l'interface python de SALOME). -* Dans la calculette, exécution d'opérations algébriques (+,-,*,/) - entre champs avec possibilité d'utiliser des scalaires dans des - opérations de type transformation linéaire (y=ax+b ou y et x sont - des champs et a et b des scalaires). Egalement quelques fonctions - mathématiques standard applicables sur des champs (pow, sqrt). -* Possibilité de visualiser les champs produits avec VISU -* Possibilité d'exporter des champs produits dans un fichier med - -La figure ci-dessous montre le résultat d'une séquence d'utilisation -dans laquelle les champs "testfield1" et "testfield2" ont été -sélectionnés dans l'arbre d'étude pour être utilisés dans la console -textuelle sous les noms de variables f1 et f2. L'image montre le -contrôle visuel du résultat de l'opération f1+f2-(f1-f2)^2 tapée en -ligne de commande: - -.. image:: images/medop-gui-result.png - :align: center - -La séquence ci-après montre le cas d'utilisation complet en -images: - -1. Sélection d'un champs sur un pas de temps dans l'arbre d'étude -2. Saisie d'un nom de variable (alias) pour manipuler ce champ. Par - défaut, le nom du champ est proposé (``testfield1`` ici). Dans - l'exemple, l'utilisateur remplace par l'alias ``f1``. -3. Contrôle visuel du champ ``testfield1`` manipulé par sa variable - ``f1`` au moyen de la commande ``f1.visu()`` -4. Chargement du champ ``testfield2`` sous le nom ``f2``, exécution de - l'opération ``f1+f2-(f1-f2)^2`` et contrôle visuel du résultat, - récupéré ici dans une variable de nom ``result``. - -.. |IMG_SELECT| image:: images/medop-gui-selectfield_scale.png -.. |IMG_ALIAS| image:: images/medop-gui-aliasfield_scale.png -.. |IMG_VISU| image:: images/medop-gui-visufield_scale.png -.. |IMG_RESULT| image:: images/medop-gui-result_scale.png - -+---------------+---------------+ -| |IMG_SELECT| | |IMG_ALIAS| | -+---------------+---------------+ -| |IMG_VISU| | |IMG_RESULT| | -+---------------+---------------+ - -La solution technique est construite sur les principes suivants: - -* Les données MEDMEM sont physiquement chargées par le composant MED, - c'est-à-dire dans le processus ``Container`` de SALOME, et sont - référencées dans l'étude SALOME. -* Les opérations sont physiquement des opérations entre objets MEDMEM - purs qui ont lieu dans le composant MED. -* Les opérations sont pilotées par des objets proxy python instanciés - dans la console TUI puis manipulés par l'utilisateur. Ces objets - proxy savent accéder aux objets MEDMEM au travers de leur interface - CORBA. - -Ainsi, l'architecture technique est construite pour pouvoir travailler -sur des données MEDMEM pur en partant de pointeurs CORBA manoeuvrés -depuis des objets python dans l'interface textuelle de -SALOME. L'effort principal a donc porté sur la mise au point de -l'interface technique qui permet de lier des variables représentant -les champs au niveau du GUI (techniquement, la calculette est -l'interpréteur python embarqué dans le GUI, étendu de quelques -fonctions pour la manipulation de champs), alors que les données -MEDMEM sont physiquement disponibles uniquement au niveau des -composants CORBA (et les opérations implémentées dans MEDMEM -uniquement). - -Pour le moment, la maquette est limitée à des operations entre champs -qui partagent le même support med (contrainte de MEDMEM) et le -résultat est calculé sur toutes les composantes et tout le domaine de -définition du champs (cette deuxième contrainte est juste parce que -les extentions n'ont pas encore été examinées). Enfin, le support de -gestion des données est supposé être l'étude SALOME et la structure -MED qui y est publiée. diff --git a/src/MEDOP/doc/sphinx/xmed-references.rst b/src/MEDOP/doc/sphinx/xmed-references.rst deleted file mode 100644 index 30d66ec7f..000000000 --- a/src/MEDOP/doc/sphinx/xmed-references.rst +++ /dev/null @@ -1,28 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -ANNEXE: Références documentaires -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -.. include:: xmed-definitions.rst - -Documents de référence: - -* |REF_EDF_VCA_H-I2C-2009-03595-FR|_ - Valérie Cano - décembre 2009 -* |REF_CEA_VBE_MEDMEM|_ - Vincent Bergeaud - janvier 2007 -* |LINK_EDF_MEDDOC|_ - documentation en ligne (EDF) - -Présentations: - -* |REF_EDF_PRESMANIPCHP01|_ - Valérie Cano, Guillaume Boulant - janvier 2010 -* |REF_EDF_PRESMANIPCHP02|_ - Guillaume Boulant - octobre 2010 -* |REF_EDF_PRESMANIPCHP03|_ - Guillaume Boulant - mars 2011 -* Présentation à la Journée des Utilisateurs de SALOME de 2011 (JUS2011): - - - |REF_EDF_JUS2011_PDF|_ - Anthony Geay (CEA), Guillaume Boulant - novembre 2011 - - |REF_EDF_JUS2011_OGV1|_ - - |REF_EDF_JUS2011_OGV3|_ - - |REF_EDF_JUS2011_OGV4|_ - -Notes de travail: - -* |REF_EDF_GBO_WORKNOTE|_ - Guillaume Boulant - novembre 2010 -* |REF_EDF_ELO_REM|_ - Eric Lorentz - novembre 2010 diff --git a/src/MEDOP/doc/sphinx/xmed-specifications.rst b/src/MEDOP/doc/sphinx/xmed-specifications.rst deleted file mode 100644 index 1f8cdabaf..000000000 --- a/src/MEDOP/doc/sphinx/xmed-specifications.rst +++ /dev/null @@ -1,918 +0,0 @@ -.. meta:: - :keywords: maillage, champ, manipulation, med - :author: Guillaume Boulant - -.. include:: xmed-definitions.rst - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Module XMED: Spécifications fonctionnelles et techniques -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -(|XMED_SPECIFICATIONS_PDF|_) - -Ce texte présente les spécifications informatiques pour le -développement d'un module de manipulation de champs qui répond à -l'expression de besoins formulée dans le cahier des charges -|REF_EDF_VCA_H-I2C-2009-03595-FR|_. - -.. contents:: Sommaire - :local: - :backlinks: none - -Description des cas d'application de référence -============================================== - -Plusieurs cas d'applications métier sont identifiés pour piloter le -développement du module de manipulation de champs: - -* **Analyser et post-traiter le résultat d'un calcul**. C'est l'usage - principal qui consiste typiquement à créer des champs comme le - résultat d'*opérations mathématiques* dont les opérandes sont des - champs et des scalaires. On compte également dans cette catégorie - les *opérations de restriction* qui permettent d'extraire puis - utiliser une partie d'un champs, c'est-à-dire de créer un champ - comme la restriction d'un autre champ à une partie de son domaine de - définition (certaines composantes, certains pas de temps, limitation - à un groupe de mailles). -* **Comparer des champs issus d'un calcul paramétrique**. Il s'agit - d'une variante du cas précédent qui consiste à mesurer et visualiser - les variations entre des champs issues de sources de données - différentes (différents fichiers med). -* **Préparer les conditions aux limites d'une calcul**. Il s'agit de - pouvoir initialiser un champ sur un maillage ou un groupe de - mailles, c'est-à-dire créer un champ de toute pièce sur un - support spatial donné, par exemple par la donnée d'une fonction - mathématique qui donne les valeurs des composantes en fonction des - coordonnées spatiales. -* **Gérer des données de calcul**. Il s'agit typiquement de pouvoir - rassembler au sein d'un même fichier med des champs et des maillages - issues de différentes sources de données, et/ou créés au travers des - cas d'application présentés ci-dessus. - -Modèle conceptuel des données -============================= - -On rappelle ici les concepts utilisés dans le module et les modalités -d'utilisation de ces concepts. Le point de vue est celui de -l'utilisateur du module de manipulation de champs. Il s'agit -essentiellement pour le moment d'éclaircir l'ergonomie d'usage sur le -plan conceptuel, avant d'aborder la déclinaison en spécifications -techniques pour lesquelles les particularités du modèle MED devront -être intégrées à la réflexion. - -Concept de champ ----------------- - -Le concept central est celui de *champ*, c'est-à-dire une grandeur -physique exprimée sur un domaine spatial D. La grandeur peut être de -type scalaire (une température), de type vectorielle (une vitesse) ou -de type tensorielle (les contraintes). En un point de l'espace, elle -se définie donc par la donnée d'une ou plusieurs valeurs numériques -appelées les *composantes* (1 pour un champ scalaire, 3 pour un champ -vectoriel 3D, 6 pour un champ tensoriel symétrique 3D). - -.. note:: Une pratique courante au niveau des codes est de stocker - plusieurs grandeurs physiques différentes dans un même champs med - (au sens informatique du terme). Par exemple, le champ - électromagnétique à 6 composantes, plus le champ de température - scalaire peuvent techniquement être stockés dans un même champs med - à 7 composantes. C'est pourquoi, le module de manipulation de - champs doit fournir des fonctions de restrictions qui permettent - d'extraire certaines composantes pour former la grandeur physique à - étudier. Dans la suite du document, on part du principe que l'on - peut se ramener dans tous les cas au cas d'un champ homogène tel - que défini plus haut. - -Dans le cadre d'un modèle numérique discret, les valeurs du champ sont -exprimées pour un nombre fini de positions, qui correspondent à des -lieux particuliers du maillage. Suivant la nature des modèles de -calcul, les valeurs peuvent être données par cellule, par face, par -noeud, aux points de gauss, ... - -Ainsi, un champ discret est un objet dont les valeurs peuvent être -lues selon les dimensions suivantes: - -* *La position p dans l'espace*, caractérisée par le type de l'élément - de maillage support et son numéro identifiant -* *La composante c*, caractérisée par son indice (jusqu'à 6 - composantes dans les modèles physiques envisagés) - -L'évolution d'un champ dans le temps peut être exprimée sous la forme -d'une série temporelle, c'est-à-dire une séquence de champs donnés -pour des instants discrets. Aussi, si l'on manipule un champ qui varie -dans le temps, l'accès aux valeurs introduit une dimension -supplémentaire: - -* *Le temps t*, caractérisé par un numéro de pas de temps - (correspondant en général à une étape du calcul qui a produit le champ). - -.. note:: Il s'agit là d'une représentation conceptuelle standard dont - le |LINK_EDF_MEDDOC|_ fait une expression détaillée. En - particulier, la position p est déterminée par la donnée du type - d'élément support (valeurs aux noeuds, aux mailles, aux noeuds par - éléments, aux points de gauss) et de l'indice de cet élément. En - général, le type d'éléments support est résolu à l'initialisation - et l'indice peut suffire au repérage dans les algorithmes. Le temps - t est déterminé par un numéro d'itération, qui peut éventuellement - être complété par un numéro d'ordre. Le cas des points de gauss - ajoute un cran de complexité dans la mesure où il faut repérer - l'entité géométrique (maille, face, arrête) puis le point de gauss - de cette entité. A noter que dans le modèle MED, le concept de - série temporelle de champ n'est pas explicitement définie et - l'accès à des valeurs à différents instants t1 et t2 nécessite le - chargement des champs ``F1=F(t1)`` et ``F2=F(t2)``. - -Par convention, on utilisera par la suite les notations: - -* **U(t,p,c)** pour désigner la valeur de la composante c d'un champ U - à la position p et prise à l'instant t; -* **U(t,p,:)** pour signifier que l'on manipule l'ensemble de toutes - les composantes; -* **U(t,:,c)** pour signifier que l'on manipule le domaine de - définition spatial complet. - -Dans une grande majorité des cas d'usage on travaille à temps t fixé -et sur un domaine spatiale prédéfini. Aussi on utilisera également la -notation à deux arguments ``U(:,:)`` ou tout simplement ``U`` (dès -lors qu'il n'y a pas ambiguïté) pour désigner un champ complet et Uc -pour désigner la composante c du champ avec c=1..6. - -Concept d'opération -------------------- -Le deuxième concept à préciser est la notion d'*opération*. Une -opération dans le présent contexte est l'application d'un opérateur -sur un ou plusieurs champs pour produire une grandeur de type champ ou -de type valeur numérique. - -Par exemple, la formule ``W=OP(U,V)`` indique que le champ W est formé -à partir des champs U et V en arguments d'une fonction OP. Dans le cas -d'une opération algébrique comme l'addition (cf. :ref:`Spécification -des opérations`, le résultat attendu par défaut -est que pour chaque instant t, chaque position p et chaque composante -c, on a ``W(t,p,c)=U(t,p,c)+V(t,p,c)`` (que l'on peut noter également -``W(:,:,:)=U(:,:,:)+V(:,:,:)`` compte-tenu de la convention présentée -plus haut). Ce n'est cependant pas une règle et l'utilisateur peut -très bien manoeuvrer les champs en détaillant et mixant les -composantes (par exemple ``W(:,:,3)=5+U(:,:,1)*V(:,:,2)``), ou encore -ne travailler que sur un domaine spatial et/ou temporel particulier -(cf. |REF_EDF_VCA_H-I2C-2009-03595-FR|_ §5.4.1). - -On formalise donc le concept d'opération par les propriétés suivantes: - -* L'opérateur peut produire un champ (par exemple la somme de deux - champs W=sum(U,V)=U+V), une valeur numérique (par exemple la moyenne - spatiale d'un champ m=smoy(U)) ou une valeur logique (par exemple le - test d'égalité de deux champs b=isequal(U,V)); -* L'opérateur peut être paramétré par la donnée de valeurs numériques - (par exemple, le changement d'unité peut être défini comme une - multiplication par un scalaire V=multiply(U,1000)=1000*U); -* L'opérateur est caractérisé par un domaine d'application qui - spécifie la portée de l'opération. Ce domaine comporte plusieurs - dimensions: - - - Un domaine temporel T qui spécifie les pas de temps sur lesquels - l'opération est appliquée; - - Un domaine spatial D qui spécifie la limite de portée de - l'opérateur et donc le domaine de définition du champ produit (qui - correspond dans ce cas à une restriction du domaine de définition - des champs en argument); - - Un domaine de composantes C qui spécifie les composantes sur - lesquelles l'opération est appliquée; - -.. note:: - Sur le plan informatique, l'opérateur aura également un paramètre - appelé *option* qui pourra indiquer par exemple dans une - opération unaire V=F(U) si le résultat V est une nouvelle instance - de champ ou la valeur modifiée du champ de départ U. Il pourra - également être amené à manoeuvrer des paramètres de type chaîne de - caractères, par exemple pour les opérations de changement de nom - des champs. - -De manière générale, on utilisera la notation -**(W|y)=OP[D,C,T](P,U,V,...)** pour désigner une opération OP: - -* **(V|y)**: V ou y désignent respectivement un résultat de type - champ ou de type valeur numérique ou logique; -* **[T,D,C]**: le domaine d'application de l'opérateur avec T le - domaine temporel, D le domaine spatial et C le domaine des - composantes; -* **P,U,V,...**: les paramètres numériques P (liste de valeurs - numériques) et les champs U,V,... en arguments de l'opérateur; - -On note également les particularités suivantes pour certaines -opérations: - -* Le domaine de définition du champ produit par une opération peut - être différent du domaine de définition des champs en argument. Par - exemple, dans le cas d'une opération de projection de champ, le - domaine spatial résultat peut être modifié par rapport au domaine de - définition initial, soit par la modification de la zone géométrique, - soit par modification des entités de maillage support. -* En dehors des opérations de type dérivée et intégrale, les valeurs - résultats sont déterminées de manière locale en chaque point du - domaine d'application. Par exemple, l'addition W=U+V consiste à - produire un champ W dont les valeurs en chaque point p sont la somme - des valeurs des composantes de U et V en ce point p: ``W=U+V <=> - W(:,p,:)=U(:,p,:)+V(:,p,:)`` pour tout point p du domaine - d'application D. - -Concept de domaine d'application --------------------------------- - -Un domaine d'application est associé à une opération (et non pas à un -champ). Il a pour objectif de restreindre la portée de l'opération en -terme spatial, temporel, jeu des composantes. - -Pour ce qui concerne le domaine spatial D, plusieurs modalités de -définition sont envisagées: - -* la donnée d'un maillage ou d'un groupe d'éléments du maillage; -* un système de filtres qui peut combiner: - - - une zone géométrique définie indépendamment du maillage (boîte - limite par exemple), - - des critères conditionnant le calcul (par exemple U(t,p,c)=1 si - V(t,p,c)>> r=fa+fb - -* Effectuer les contrôles visuel et les diagnostics en ligne de - commandes python (cf. :ref:`Spécification des fonctions de - visualisation`):: - - >>> view(r) - -* Enregistrer les champs produits dans l'espace de travail sous forme - de fichier med. - -Sur cette base, on peut envisager une grande variété de cas d'utilisation: - -* La structure MED (champs, maillage et groupes de mailles) est - chargée dans le dataspace (l'étude SALOME techniquement) et peut - être explorée au niveau de l'arbre d'étude. L'arbre peut faire - apparaître: - - - les maillages et les groupes (qui peuvent être utilisés - éventuellement pour restreindre le domaine d'application) - - les champs dont on peut explorer les composantes et les itérations - -* On sélectionne plusieurs champs, éventuellement en sélectionnant les - pas de temps, les composantes et les domaines d'application spatiaux -* Menu contextuel --> Modifier un champ, Créer un champ, Prolonger un - champ, .... -* On choisi pour la suite "Créer un champ", une fenêtre de dialogue - s'affiche avec les saisies préremplies avec les données - sélectionnées. Il est possible de rajouter des éléments ou préciser - le domaine d'application -* Une partie de la boîte de dialogue est réservée à la saisie de la - ligne de commande python qui permet la création du nouveau champ. Le - nom dans l'étude pour le nouveau champ, ainsi que son nom python, - sont spécifié par l'utilisateur ({{H|un peu à la mode du module - system}}). -* L'opération est exécutée dans l'espace utilisateur (l'interface - python), de sorte que les variables soient projetées dans cet espace - et manipulables après l'opération au besoin. Par ailleurs, - l'utilisateur peut visualiser les ligne de commandes nécessaires à - taper pour exécuter sa requête. - -.. _specification_visualisation: - -Spécification des fonctions de visualisation -============================================ - -Dans le cadre du module MED, on appelle *fonction de visualisation* -une fonction qui permet d'avoir un aperçu graphique d'un champ, par -exemple au moyen d'une carte de champ construite sur une de ses -composante. Il s'agit là de vue de contrôle pour avoir une idée rapide -de la forme du champs. Pour créer des représentations spécifiques, on -préférera passer par les fonctions d'export vers le module PARAVIS. - -Les modules VISU et PARAVIS offre des interface de programmation C++ -et python qui permettent le pilotage depuis un module tiers comme le -module MED. On peut donc envisager une fonction de visualisation -intégrée au module de manipulation de champs, c'est-à-dire que l'on -déclenche sans sortir du module MED, et qui exploite les fonctions de -visualisation des modules VISU et/ou PARAVIS. - -Les captures d'écran ci-dessous illustrent la mise en oeuvre de la -fonction de visualisation: - -* Sélection d'un champ pour faire apparaitre le menu contextuel et - choisir l'option "Visualize": - -.. image:: images/xmed-gui-datasource-visualize_70pc.png - :align: center - -* Cette option déclenche l'affichage d'une carte de champ sur le cadre - d'affichage des viewers SALOME: - -.. image:: images/xmed-gui-datasource-visualize-result_70pc.png - :align: center - -Cette fonction est également disponible en ligne de commandes de -l'interface textuelle. Par exemple si ``f4`` désigne un champ de -l'espace de travail (importé des données source ou construit par les -opérations de champs), alors, on obtient une carte de champ par la -commande:: - - >>> view(f4) - -On peut remarquer d'ailleurs sur la capture d'écran de droite -ci-dessus que la demande de visualisation déclenche l'exécution de la -commande ``view`` dans la console de travail sur un champ identifié -par son numéro (3 dans l'exemple). - -.. note:: Tous les champs, qu'ils soient des champs chargés d'une - source de données ou construits par des opérations de champs sont - identifiés par un numéro unique et invariant tout au long de la - session de travail. - -Spécification des fonctions de persistance -========================================== - -On adopte le principe de fonctionnement suivant: - -* Le module n’assure pas la persistence au sens SALOME du terme, - c’est-à-dire qu’il ne permet pas la sauvegarde du travail dans une - étude au format hdf, ni le dump sous la forme de script python - SALOME. Le besoin n'est pas avéré et on peut même dire que ça n'a - pas de sens compte-tenu de l'usage envisagé pour le module MED. -* Par contre, le module fournit des fonctions de sauvegarde du travail - sous forme de fichiers med, l’export vers les modules VISU et - PARAVIZ, ou même la sauvegarde de l’historique de l’interface de - commandes. - -Ainsi donc, l'utilisateur aura une fonction (probablement graphique) -pour définir la sélection des champs de l'espace de travail à -sauvegarder. - -Spécification des fonctions d'export -==================================== - -.. warning:: EN TRAVAUX. - -Plusieurs export peuvent être proposés: - -* Export des champs vers le module PARAVIZ, dans l'objectif par - exemple d'en faire une analyse visuelle plus poussée qu'avec les - cartes de champs disponibles par défaut dans le module MED -* Export des données sous forme de tableau numpy, par exemple pour - permettre un travail algorithmique sur les valeurs des champs. - -Spécifications techniques -========================= - -Il s'agit d'exprimer ici les contraintes techniques applicables à la -conception et au développement du nouveau module MED. - -Implantation technique du module --------------------------------- - -Il est convenu que le module MED existant dans la plate-forme SALOME -incarne le module de manipulation de champ. Dans la pratique, il -s'agit d'identifier clairement les parties à conserver, d'une part, -puis les parties à re-écrire, d'autre part. On peut partir sur les -hypothèses techniques suivantes: - -* Le noyau du module en charge des opérations de manipulation de - champs proprement dites est construit sur la base des paquets - logiciels MEDCoupling (lui-même basé sur le INTERP_KERNEL) et - MEDLoader. -* L'interface graphique du module MED est complétement re-écrite et - remplacée par une interface adaptée spécialement à la manipulation - des champs et la gestion des données associées -* Le contrôle visuel pourra être déclenché dans les visualisateurs - SALOME (servis par les modules VISU et/ou PARAVIZ); -* Le module n'assure pas la persistence au sens SALOME du terme, - c'est-à-dire qu'il ne permet pas la sauvegarde du travail dans une - étude au format hdf, ni le dump sous la forme de script python - SALOME. -* Par contre, il fournit des fonctions de sauvegarde du travail sous - forme de fichiers med, l'export vers les modules VISU et PARAVIZ, ou - même la sauvegarde de l'historique de l'interface de commandes. - -L'implantation technique des développements est représentée sur la -figure ci-dessous: - -.. image:: images/xmed-implantation.png - :align: center - -Le schéma représente les packages logiciels qui composent le module -MED (cf. |REF_CEA_VBE_MEDMEM|_): - -* La partie MEDMEM, représentées en blanc. Cette partie est conservée - pour compatibilité ascendante au niveau des applications métier qui - ont fait le choix historique de s'appuyer sur MEDMEM. Cette partie - du module MED aura tendance à disparaitre dans le futur au bénéfice - de MEDCoupling et MEDLoader. -* La partie MEDCoupling, représentée en orange et qui founrnit le - modèle MED mémoire de référence (composé de maillage et de champs) - et l'interface de programmation pour manipuler le modèle. Le paquet - MEDLoader est une extention dédiée à la persistence au format med - fichier (lecture et écriture de champs et de maillage dans des - fichiers med). -* La partie à développer pour la manipulation de champ, représentée en - bleu. - -.. note:: MEDCoupling peut être vu comme une structure de donnée - particulièrement adaptée à la manipulation des gros volumes de - données, en particulier par l'exploitation des possibilités de - parallélisation et la réduction de la tailles des structures de - données. En contrepartie, elle peut présenter un périmètre - fonctionnel moins large que MEDMEM. Pour cette raison, MEDMEM avait - été choisi comme socle de développement du prototype en 2010: - - * MEDCoupling ne permet pas de gérer des maillages composés de - plusieurs type de mailles et il est exclus de le faire évoluer - dans ce sens (c'est un choix fait pour les objectifs de - performances évoqués plus haut); - * MEDCoupling ne permet pas de gérer les supports qui expriment les - champs aux noeuds par élément ni aux points de gauss. Cette - seconde limitation a disparu en 2011. - - Aujourd'hui, on fait clairement le choix de MEDCoupling pour sa - qualité et sa robustesse, dans l'objectif d'une meilleure - maintenance à long terme. Par ailleurs, les différences - fonctionnelles avec MEDMEM, si elles existaient encore en 2012 pour - les besoins de la manipulation de champs, pourront être résorbées - dans un futur proche. - - diff --git a/src/MEDOP/doc/sphinx/xmed-userguide.rst b/src/MEDOP/doc/sphinx/xmed-userguide.rst deleted file mode 100644 index f35266013..000000000 --- a/src/MEDOP/doc/sphinx/xmed-userguide.rst +++ /dev/null @@ -1,749 +0,0 @@ -.. meta:: - :keywords: maillage, champ, manipulation, guide utilisateur - :author: Guillaume Boulant - -.. include:: xmed-definitions.rst - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Module XMED: Guide d'utilisation -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -(|XMED_USERGUIDE_PDF|_) - -Ce document est un guide rapide pour l'utilisation du module MED. Il -montre comment utiliser le module sur la base de quelques exemples de -référence, inspirés des cas d'utilisation identifiés lors de l'analyse -des besoins en matière de manipulation de champs. - -.. warning:: Le document est autonome, mais il est vivement conseillé - de parcourir au préalable (ou en parallèle) :doc:`le document de - spécifications`, au moins pour fixer les - concepts et la terminologie. - -.. contents:: Sommaire - :local: - :backlinks: none - -Présentation générale du module XMED -==================================== - -L'ergonomie générale d'utilisation du module de manipulation de champs -est inspirée des logiciels comme octave ou scilab. Elle associe une -interface graphique, pour sélectionner et préparer les données, avec -une interface texte (la console python) pour le travail effectif sur -les données. - -Pour cela, le module propose deux espaces utilisateurs qui sont -symbolisés par les rectangles rouges et vert sur la capture d'écran -ci-dessous: - -* **l'espace des données** (*dataspace*), dans lequel l'utilisateur - définit les sources de données med (*datasource*), c'est-à-dire les - fichiers med dans lesquels sont lus les champs et maillages. Cet - espace permet l'exploration des maillages et des champs fournis par - les différentes sources de données. -* **l'espace de travail** (*workspace*), dans lequel l'utilisateur - peut déposer des champs sélectionnées dans l'espace source, pour - ensuite les travailler par exemple pour produire des nouveaux champs - au moyen des fonctions de manipulation fournies par l'interface - textuelle (console python TUI). - -.. image:: images/xmed-gui-withframe.png - :align: center - -L'utilisation type des fonctions de manipulation de champs suit un -processus de la forme suivante: - -1. Chargement d'un fichier med dans l'espace de données (dataspace) et - exploration du contenu, composé de maillages et de champs définis - sur ces maillages et pouvant contenir un ou plusieurs pas de temps. -2. Sélection (graphique) des champs à manipuler dans l'espace de - travail (workspace), avec la possibilité de préciser des - restrictions d'utilisation (pas de temps, composantes, groupe de - maille). -3. Création de nouveaux champs par l'exécution d'opérations - algébriques (+,-,*,/) entre champs, l'application de fonctions - mathématiques standard (pow, sqrt, abs), ou encore l'initialisation - "from scratch" sur un maillage support. -4. Contrôle visuel rapide des champs produits (avec les modules VISU - et/ou PARAVIS de SALOME, pilotés automatiquement depuis l'interface - utilisateur) -5. Enregistrement d'une partie des champs produits dans un fichier med - - -Tour rapide des fonctions du module XMED -======================================== - -Cette section présente des exemples d'utilisation du module XMED sous -la forme de "storyboard", et illustre au passage les fonctions mises à -disposition par le module. - -.. warning:: Cette section est en travaux. Tant que cet avis n'aura - pas disparu, veuillez en considérer le plan et le contenu encore - incomplets, temporaires et sujets à caution. - -Exemple 1: Explorer des sources de données ------------------------------------------- - -.. note:: Cet exemple présente les fonctions: - - * ajouter une source de données - * fonctions "Extends field series", "Visualize" - -.. |ICO_DATASOURCE_ADD| image:: images/ico_datasource_add.png - :height: 16px - -.. |ICO_XMED| image:: images/ico_xmed.png - :height: 16px - -.. |ICO_DATASOURCE_EXPAND| image:: images/ico_datasource_expandfield.png - :height: 16px - -.. |ICO_DATASOURCE_VIEW| image:: images/ico_datasource_view.png - :height: 16px - -Au démarrage, le module de manipulation de champs, identifié par -l'icône |ICO_XMED|, présente une interface vierge: - -.. image:: images/xmed-gui-start.png - :align: center - :width: 800px - -La première étape consiste à ajouter une ou plusieurs source de -données med dans le "dataspace". Pour cela, on clique sur l'icône "Add -datasource" |ICO_DATASOURCE_ADD| qui propose de sélectionner un -fichier med: - -.. image:: images/xmed-gui-datasource-selectfile.png - :align: center - :width: 800px - -L'opération ajoute une nouvelle entrée (datasource) dans l'espace de -données (dataspace). Le contenu peut être exploré en parcourant -l'arborescence. La figure ci-dessous (image de gauche) montre le -résultat du chargement du fichier ``timeseries.med`` contenant un -maillage de nom ``Grid_80x80`` sur lequel est défini un champ au noeud -de nom ``Pulse``. Par défaut, la composition du champs (en terme de -pas de temps et de composantes) n'est pas affichée pour éviter -l'encombrement visuel de l'arbre. On doit faire la demande explicite -au moyen de la commande "Expand field timeseries" -|ICO_DATASOURCE_EXPAND| disponible dans le menu contextuel associé aux -champs. Le résultat est affiché sur l'image centrale. La liste des -itérations du champ ``Pulse`` peut être consultée. - -.. |IMG_DATASOURCE_EXPLORE| image:: images/xmed-gui-datasource-explore-zoom.png - :height: 340px -.. |IMG_DATASOURCE_MENUCON| image:: images/xmed-gui-datasource-menucontextuel-zoom.png - :height: 340px -.. |IMG_DATASOURCE_EXPANDF| image:: images/xmed-gui-datasource-expand-zoom.png - :height: 340px - -+--------------------------+--------------------------+--------------------------+ -| |IMG_DATASOURCE_EXPLORE| | |IMG_DATASOURCE_MENUCON| | |IMG_DATASOURCE_EXPANDF| | -+--------------------------+--------------------------+--------------------------+ - -.. note:: En toute rigueur, le concept de *champ* dans le modèle MED - désigne une itération donnée. Un ensemble d'itérations est désigné - par le terme *série temporelle de champs*. Par abus de langage, et - s'il n'y a pas ambiguité, on utilisera le nom du champ pour - désigner à la fois le champs proprement dit ou la série temporelle - à laquelle il appartient. - -Enfin, il est possible au niveau du dataspace de visualiser la forme -générale du champ au moyen d'une carte scalaire affichée dans le -viewer de SALOME. Pour cela, on sélectionne le pas de temps à -visualiser et on utilise la commande "Visualize" |ICO_DATASOURCE_VIEW| -disponible dans le menu contextuel associé: - -.. image:: images/xmed-gui-datasource-visualize-zoom.png - :align: center - :width: 800px - -.. note:: Cette représentation graphique a pour objectif le contrôle - visuel rapide. Aussi, les fonctions du module VISU sont employées - par défaut, mais il est possible de faire l'affichage des cartes - scalaires au moyen du module PARAVIS (choix de préférence non - implémenté pour le moment, mais techniquement réalisable). - -Exemple 2: Rassembler des champs issus de différentes sources -------------------------------------------------------------- - -.. note:: Cet exemple présente les fonctions: - - * fonction "Use in workspace" - * fonction "Save" - -.. |ICO_DATASOURCE_USE| image:: images/ico_datasource_use.png - :height: 16px -.. |ICO_WORKSPACE_SAVE| image:: images/ico_workspace_save.png - :height: 16px - -L'objectif est de récupérer des données issues de différents fichiers -med, puis de les rassembler dans un même fichier en sortie. - -On commence par ajouter les sources de données med dans l'espace de -données (dataspace). Dans l'exemple ci-dessous, l'espace de données -contient deux sources de nom ``parametric_01.med`` et -``smallmesh_varfiled.med``. La première source contient le maillage -``Grid_80x80_01`` sur lequel est défini le champ ``StiffExp_01``. La -deuxième source contient le maillage ``My2DMesh`` sur lequel sont -définis deux champs de noms respectifs ``testfield1`` et -``testfield2``: - -.. image:: images/xmed-userguide-example2-datasource.png - :align: center - :width: 800px - -Pour l'exemple, on souhaite rassembler les champs ``StiffExp_01`` et -``testfield2`` dans un fichier de nom ``result.med``. La procédure -consiste à importer les deux champs dans l'espace de travail -(workspace), puis à sauvegarder l'espace de travail. Pour cela, on -sélectionne les champs et on utilise la commande "Use in workspace" -|ICO_DATASOURCE_USE| disponible dans le menu contextuel. Les deux -champs sélectionnés apparaissent dans l'arborescence de l'espace de -travail: - -.. image:: images/xmed-userguide-example2-workspace.png - :align: center - :width: 800px - -La sauvegarde de l'espace de travail est faite au moyen de la commande -"Save workspace" |ICO_WORKSPACE_SAVE| disponible dans la barre -d'outils du module. Une fenêtre de dialogue invite l'utilisateur à -spécifier le nom du fichier de sauvegarde: - -.. image:: images/xmed-userguide-example2-workspace-save.png - :align: center - :width: 800px - -Ce fichier ``result.med`` peut ensuite être rechargé dans le module -XMED (ou les modules VISU ou PARAVIS) pour vérifier la présence des -champs sauvegardés. - -.. BUG: plantage à l'utilsation dans XMED d'un fichier rechargé -.. (invalid mesh on field) - -.. _xmed.userguide.exemple3: - -Exemple 3: Appliquer une opération mathématique sur des champs --------------------------------------------------------------- - -.. note:: Cet exemple présente les fonctions: - - * exécution d'opérations mathématiques dans la console TUI - * fonction "put" pour référencer un champ de travail dans la liste - des champs persistant. - * fonction "Visualize" depuis le TUI. - -L'usage le plus courant du module de manipulation de champs est -d'exécuter des opérations mathématiques dont les opérandes sont des -champs ou des composantes de ces champs. - -On se place dans une situation où les sources de données sont définies -dans le "dataspace" (dans l'exemple ci-après, une série temporelle de -nom ``Pulse``, contenant 10 pas de temps, définis sur un maillage de -nom ``Grid_80x80``, le tout issu du datasource ``timeseries.med``). - -Comme vu précedemment, pour manoeuvrer un champ dans l'espace de -travail, on sélectionne ce champ, puis on exécute la commande "Use in -workspace" |ICO_DATASOURCE_USE| du menu contextuel. Dans le cas -présent, un seul champ est sélectionné (contre deux dans l'exemple -précédent) et la commande ouvre alors une fenêtre de dialogue qui -permet de préciser les données sur lesquelles on souhaite -effectivement travailler et comment on veut les manoeuvrer: - -.. image:: images/xmed-gui-datasource-useinworkspace-alias.png - :align: center - :width: 800px - -.. note:: En l'état actuel du développement, l'interface propose - uniquement de définir le nom de la variable sous laquelle doit être - manoeuvré le champ dans la console de travail (TUI). Dans une - version ultérieure, il est prévue de pouvoir préciser la ou les - composante du champs à utiliser et un groupe de maille pour définir - une restriction géométrique. Inversement, il sera également - possible de choisir une série temporelle complète pour faire des - opérations globales sur l'ensemble des pas de temps. - -Aprés validation, le champ est placé dans l'arborescence du -"workspace" et une variable de nom ```` est créée -automatiquement dans la console de travail pour désigner le -champ. Dans cet exemple, ```` vaut ``f3``, positionné ainsi par -l'utilisateur pour rappeler que la variable correspond au pas de temps -n°3: - -.. image:: images/xmed-gui-workspace.png - :align: center - :width: 800px - -La manipulation peut commencer. Dans l'exemple ci-dessous, on crée le -champ ``r`` comme le résultat d'une transformation afine du champ -``f3`` (multiplication du champ par le facteur 2.7 auquel on ajoute -l'offset 5.2):: - - >>> r=2.7*f3+5.2 - -On peut poursuivre la manipulation du champs avec une variété -d'opérations qui sont détaillées dans les spécifications du module -(cf. :ref:`Spécification des opérations`): - - >>> r=f3/1000 # les valeurs de r sont celles du champ f3 réduites d'un facteur 1000 - >>> r=1/f3 # les valeurs de r sont les inverses des valeurs de f3 - >>> r=f3*f3 # les valeurs de r sont celles du champ f3 élevées au carré - >>> r=pow(f3,2) # même résultat - >>> r=abs(f3) # valeur absolue du champ f3 - >>> ... - -Les opérations peuvent utiliser plusieurs opérandes de type champs. Si -``f4`` désigne le pas de temps n°4 du champ ``Pulse``, alors on peut -calculer toute combinaison algébrique des deux champs:: - - >>> r=f3+f4 - >>> r=f3-f4 - >>> r=f3/f4 - >>> r=f3*f4 - -Avec au besoin l'utilisation de variables scalaires:: - - >>> r=4*f3-f4/1000 - >>> ... - -Dans ces exemples, la variable ``r`` désigne un champ de travail qui -contient le résultat de l'opération. Par défaut, ce champ de travail -n'est pas référencé dans l'arborescence du workspace. Si on souhaite -tout de même le référencer, par exemple pour qu'il soit pris en compte -dans la sauvegarde, alors on tape la commande:: - - >>> put(r) - -La fonction ``put`` a pour but de marquer le champ en argument comme -persistent, puis de le ranger dans l'arborescence du "workspace" afin -qu'il soit visible et sélectionnable. En effet, parmi tous les champs -qui pourront être créés dans la console pendant la session de travail, -tous n'ont pas besoin d'être sauvegardés. Certains sont même des -variables temporaires qui servent à la construction des champs -résultats finaux. C'est pourquoi, seuls les champs rangés dans -l'arborescence du workspace sont enregistrés lors de la demande de -sauvegarde du workspace. - -Les variables définies dans la console ont d'autres utilités. Tout -d'abord, elles permettent d'imprimer les informations concernant le -champ manoeuvré. Pour cela, on tape simplement le nom de la variable -puis retour:: - - >>> f3 - field name (id) = Pulse (3) - mesh name (id) = Grid_80x80 (0) - discretization = ON_NODES - (iter, order) = (3,-1) - data source = file:///home/gboulant/development/projets/salome/MEDOP/XMED/xmed/resources/datafiles/timeseries.med - -Elle peut également être utilisée comme argument des commandes de -gestion disponibles dans l'interface textuelle (dont la liste -détaillée est décrite à la section :ref:`Documentation de l'interface -textuelle`). Par exemple, la fonction ``view`` -permet d'afficher la carte scalaire du champ dans le viewer:: - - >>> view(f3) - -Donne: - -.. image:: images/xmed-gui-workspace-view.png - :align: center - :width: 800px - -.. note:: On remarquera ici qu'il est facile de comparer deux pas de - temps d'un champ, par exemple en calculant la différence ``f3-f4``, - puis en affichant un aperçu de la carte scalaire résultat au moyen - de la fonction ``view``:: - - >>> view(f3-f4) - -On peut enfin tout simplement afficher les données du champs par la -commande ``print``:: - - >>> print f3 - Data content : - Tuple #0 : -0.6 - Tuple #1 : -0.1 - Tuple #2 : 0.4 - Tuple #3 : -0.1 - Tuple #4 : 0.4 - ... - Tuple #6556 : 3.5 - Tuple #6557 : 3.3 - Tuple #6558 : 1.5 - Tuple #6559 : 0.3 - Tuple #6560 : 0.2 - -Il est important de noter que les opérations entre champs ne peuvent -être faites qu'entre champs définis sur le même maillage. Il s'agit là -d'une spécification du modèle MED qui interdit d'envisager les -opérations entre champs définis sur des maillages géométriquement -différents. Techniquement, cela se traduit par l'obligation pour les -objets informatique *champs* de partager le même objet informatique -*maillage*. - -Dans l'hypothèse où on souhaite utiliser des champs définis sur des -maillages différents, par exemple pour manoeuvrer les valeurs des -champs à l'interface de deux maillages partageant une zone géométrique -2D, il faut d'abord ramener tous les champs sur le même maillage de -surface par une opération de projection. - -.. note:: Même si ceci est techniquement possible avec la bibliothèque - MEDCoupling, cet type d'opération de projection n'est pas encore - disponible dans le module de manipulation de champs (prévu en - 2012). - -Un autre besoin plus classique est l'utilisation de champs définis sur -des maillages géométriquement identiques, mais techniquement -différents, par exemple lorsqu'ils sont chargés de fichiers med -différents. Pour traiter ce cas de figure, la bibliothèque MEDCoupling -prévoit une fonction de "Changement du maillage support", dont -l'utilisation au niveau du module de manipulation de champs est -illustrée dans :ref:`l'exemple 4` ci-après. - -.. _xmed.userguide.exemple4: - -Exemple 4: Comparer des champs issues de différentes sources ------------------------------------------------------------- - -.. note:: Cet exemple présente les fonctions: - - * Changement du maillage support "change underlying mesh" - -On se place ici dans le cas de figure où des champs ont été produits -sur le même maillage, au sens géométrique, mais enregistrés dans des -fichiers med différents. C'est le cas par exemple d'une étude -paramétrique où plusieurs calculs sont effectués avec des variantes -sur certains paramètres du modèle simulé, chaque calcul produisant un -fichier med. - -Soit ``parametric_01.med`` et ``parametric_02.med`` deux fichiers med -contenant les champs que l'on souhaite comparer, par exemple en -calculant la différence des valeurs et en visualisant le résultat. - -Aprés le chargement des sources de données dans le module XMED, -l'utilisateur se trouve en présence de deux maillages, au sens -technique du terme cette fois-ci, c'est-à-dire que les champs sont -associées à des objets informatiques maillage différents, bien que -géométriquement identiques. - -Or, les fonctions de manipulation de champs ne permettent pas les -opérations sur des champs dont les maillages supports sont différents -(voir la remarque à la fin de :ref:`l'exemple -3`). - -Pour résoudre ce cas de figure, le module de manipulation de champs -met à disposition la fonction "Change underlying mesh" qui permet de -remplacer le maillage support d'un champ par un autre à partir du -moment où les deux maillages sont géométriquement identiques, -c'est-à-dire que les noeuds ont les mêmes coordonnées spatiales. - -.. |ICO_DATASOURCE_CHG| image:: images/ico_datasource_changeUnderlyingMesh.png - :height: 16px - -Dans l'exemple proposé, l'utilisateur sélectionne le premier pas de -temps du champ ``StiffExp_01`` du "datasource" ``parametric_01.med``, -puis l'importe dans l'espace de travail au moyen de la commande "Use -in workspace" |ICO_DATASOURCE_USE|. Il sélectionne ensuite le premier -pas de temps du champs ``StiffExp_02`` du "datasource" -``parametric_02.med``, mais l'importe dans l'espace de travail au -moyen de la commande "Change underlying mesh" |ICO_DATASOURCE_CHG|. La -fenêtre de dialogue ci-dessous s'affiche et invite l'utilisateur à -choisir le nouveau maillage support par sélection dans l'arborescence -du "dataspace": - -.. image:: images/xmed-gui-datasource-changeUnderlyingMesh.png - :align: center - -Dans cet exemple, on sélectionne le maillage ``Grid_80x80_01`` support -du champ ``StiffExp_01``, avec lequel on souhaite faire la -comparaison. Après validation, l'arborescence du workspace contient le -champ ``StiffExp_02`` défini sur le maillage ``Grid_80x80_01``: - -.. image:: images/xmed-gui-datasource-changeUnderlyingMesh_wsview.png - :align: center - -.. note:: La fonction "Change underlying mesh" ne modifie pas le champ - sélectionné dans le "dataspace" (principe de base de fonctionnement - du dataspace), mais crée une copie du champ dans l'espace de travail - pour ensuite remplacer le maillage support. D'où le nom par défaut - pour le champ ``dup()`` (dup pour - "duplicate"). - -Il reste à associer une variable à ce champ pour le manipuler dans la -console. Ceci peut être fait au moyen de la commande "Use in console", -disponible dans le menu contextuel du workspace. - -En définitif, si ``f1`` désigne le champ issu du datasource -``parametric_01.med`` et ``f2`` le champ issu du datasource -``parametric_02.med`` par la procédure décrite ci-dessus, alors la -comparaison des deux grandeurs peut être faite comme pour le cas de -:ref:`l'exemple 3`:: - - >>> r=f1-f2 - >>> view(r) - -.. note:: En remarque générale sur cet exemple, il convient de noter - les points suivants: - - * l'égalité géométrique de deux maillages est établie à une marge - d'erreur prés qu'il est possible de définir techniquement, mais - qui n'est pas ajustable au niveau de l'interface du module de - manipulation de champs. Elle est fixée à une valeur standard qui - permet de traiter la plupart des cas utilisateur. On verra à - l'usage s'il est nécessaire de remonter ce paramètre au niveau de - l'interface. - * L'utilisateur doit faire la démande explicite de changer le - maillage support d'un champ, en prévision de la comparaison de - champs issus de datasource différentes. Il s'agit là d'un choix - fonctionnel délibéré pour que l'utilisateur garde trace des - modifications faites sur les données (pas de modification - automatiques à l'insu de l'utilisateur, même sous prétexte - d'amélioration de l'ergonomie). - - -Exemple 5: Créer un champ sur un domaine spatial ------------------------------------------------- - -.. note:: Cet exemple présente les fonctions: - - * initialisation par une fonction de la position spatiale - * initialisation sur un groupe de maille - -Le domaine géométrique de définition du champs à créer est spécifié -ici par la donnée d'un groupe de mailles. Ce cas d'usage est -typiquement prévu pour produire les conditions de chargement initial -d'une structure, par exemple en définissant un champ sur une surface -de la géométrie, identifiée par un nom de groupe de mailles. - -.. warning:: DEVELOPPEMENT EN COURS - -Exemple 6: Extraire une partie d'un champ ------------------------------------------ - -.. note:: Cet exemple présente les fonctions: - - * extraire une composante (ou un sous-ensemble des composantes) - * extraire un domaine géométrique (valeurs sur un groupe de maille) - * extraire un ou plusieurs pas de temps. - -.. warning:: DEVELOPPEMENT EN COURS - - On doit illustrer ici les fonctions de restriction, qui - permettraient de récupérer certaines composantes uniquement. Le - principe est qu'on crée un nouveau champ qui est une restriction du - champ argument à une liste de composantes à spécifier (utiliser la - fonction __call__ des fieldproxy). - -Pour l'extraction des pas de temps, on peut se ramener au cas de -l'exemple 2 avec une seule source de donnée. - -Exemple 7: Créer un champ à partir d'une image to[mp]ographique ---------------------------------------------------------------- - -.. note:: Cet exemple présente les fonctions: - - * Création d'un champ sans datasource (ni maillage, ni champs), à - partir d'un fichier image - -En tomographie ou en topographie, les appareils de mesure produisent -des images qui représentent une grandeur physique en niveaux de gris -sur un plan de coupe donné. L'image ci-dessous représente par exemple -une vue interne du corps humain faite par IRM: - -.. image:: images/xmed-irm.png - :align: center - :width: 600px - -Cette image est un ensemble de pixels organisés sur une grille -cartesienne. Elle peut donc être modélisée sous la forme d'un champ -scalaire dont les valeurs sont définies aux cellules d'un maillage -réglés de même taille que l'image (en nombre de pixels): - -.. image:: images/xmed-irm-field.png - :align: center - :width: 600px - -Le module de manipulation de champ fournit un utilitaire appelé -``image2med.py`` qui permet d'appliquer ce principe à la conversion -d'un fichier image en fichier med contenant la représentation de -l'image sous forme d'un champ scalaire (seul le niveau de gris est -conservé):: - - $ /bin/salome/xmed/image2med.py -i myimage.png -m myfield.med - -.. |ICO_IMAGESOURCE| image:: images/ico_imagesource.png - :height: 16px - -Cette opération de conversion peut être faite automatiquement dans -l'interface graphique du module au moyen de la commande "Add Image -Source" |ICO_IMAGESOURCE| disponible dans la barre d'outils. Cette -commande ouvre la fenêtre suivante pour inviter l'utilisateur à -choisir un fichier image: - -.. image:: images/medop_image2med_dialog.png - :align: center - -Le nom du fichier med résultat est proposé par défaut (changement de -l'extention en ``*.med``) mais il peut être modifié. Enfin, on peut -demander le chargement automatique du fichier med produit pour ajout -dans l'espace de donnée. Les champs peuvent alors être manipulés comme -dans les cas d'utilisation standard. - -Par exemple, l'image ci-dessous affiche le résultat de la différence -entre deux images, ajoutée à l'image de référence: si i1 et i2 -désignent les champs créés à partir des deux images, on représente ``r -= i1 + 5*(i2-i1)`` où le facteur 5 est arbitraire et sert à amplifier -la zone d'intérêt (en haut de l'oeil gauche): - -.. image:: images/xmed-irm-diff.png - :align: center - :width: 600px - -L'exemple ci-dessous est le résultat du chargement d'une image -tomographique issue du projet MAP (Charles Toulemonde, -EDF/R&D/MMC). L'image tomographique: - -.. image:: images/champ_altitude_MAP.png - :align: center - :width: 600px - -Le résultat du chargement: - -.. image:: images/medop_image2med_tomographie.png - :align: center - :width: 800px - -Exemple 8: Continuer l'analyse dans PARAVIS -------------------------------------------- - -.. note:: Cet exemple présente les fonctions: - - * Export de champs vers le module PARAVIS. - -Les possibilités de représentation graphique des champs fournies par -le module MED ont pour seul objectif le contrôle visuel rapide. Par -défaut, le viewer de VISU est employé. - -Pour une analyse plus détaillées des champs, il est nécessaire de -poursuivre le travail dans PARAVIS. Le module de manipulation de -champs offre une fonction qui simplifie ce passage, en faisant le -chargement automatique dans PARAVIS et en proposant une visualisation -par défaut (carte de champs scalaire). - -Pour cela, il faut sélectionner dans l'espace de travail les champs à -exporter, puis déclencher la fonction d'export depuis le menu -contextuel associé: - -.. image:: images/medop_exportparavis.png - :align: center - -Les champs sélectionnés sont regroupés dans une entrée MED du -navigateur PARAVIS, et le premier champ est affiché sous forme de -carte de champ: - -.. image:: images/medop_exportparavis_result.png - :align: center - :width: 800px - -.. note:: La fonction d'export est une fonction de confort. La même - opération peut être faite manuellement en procédant d'abord à - l'enregistrement des champs sous forme de fichier MED, puis en - chargeant le fichier généré dans le module PARAVIS pour - visualisation. - -.. _xmed.userguide.tui: - -Utilisation de l'interface textuelle du moduel XMED (TUI) -========================================================= - -Toutes les opérations menées au moyen de l'interface graphique peuvent -être réalisées (avec plus ou moins de facilité) avec l'interface -textuelle. Le module de manipulation de champs peut même être utilisé -exclusivement en mode texte. Pour cela, on lance la commande:: - - $ /medop.sh - -Cette commande ouvre une console de commandes ``medop>``. Un fichier -med peut être chargé et travaillé, par exemple pour créer des champs à -partir des données du fichier. - -Que l'on soit en mode texte pur ou en mode graphique, un séquence de -travail type dans la console peut ressembler au jeu d'instructions -suivantes:: - - >>> load("/path/to/mydata.med") - >>> la - id=0 name = testfield1 - id=1 name = testfield2 - >>> f1=get(0) - >>> f2=get(1) - >>> ls - f1 (id=0, name=testfield1) - f2 (id=1, name=testfield2) - >>> r=f1+f2 - >>> ls - f1 (id=0, name=testfield1) - f2 (id=1, name=testfield2) - r (id=2, name=testfield1+testfield2) - >>> r.update(name="toto") - >>> ls - f1 (id=0, name=testfield1) - f2 (id=1, name=testfield2) - r (id=2, name=toto) - >>> put(r) - >>> save("result.med") - -Les commandes principales sont: - -* ``load``: charge un fichier med dans la base de données (utile - uniquement en mode texte pur):: - - >>> load("/path/to/datafile.med") - -* ``la``: affiche la liste de tous les champs chargés en base de données ("list all") -* ``get``: définit un champ dans l'espace de travail à partir de son - identifiant (utile plutôt en mode texte pur car l'interface - graphique permet de faire cette opération par sélection d'un champ - dans le dataspace):: - - >>> f=get(fieldId) - -* ``ls``: affiche la liste des champs présent dans l'espace de travail ("list") -* ``put``: met un champ en référence dans l'*espace de gestion*:: - - >>> put(f) - -* ``save``: sauvegarde tous les champs référencés dans l'espace de - gestion dans un fichier med:: - - >>> save("/path/to/resultfile.med") - -.. note:: On peut faire à ce stade plusieurs remarques: - - * la commande ``load`` charge uniquement les méta-informations - décrivant les maillage et les champs (noms, type de - discrétisation, liste des pas de temps). Les maillages et les - valeurs physiques des champs sont chargées ultérieurement (et - automatiquement) dés lors qu'elles sont requises par une - opération. Dans tous les cas, les données med (méta-informations - et valeurs) sont physiquement stockées au niveau de l'espace - *base de données*. - * la commande ``get`` définit en réalité un *manipulateur de champ* - dans l'espace de travail, c'est-à-dire une variable qui fait la - liaison avec le champ physique hébergé dans la base de - données. Les données physiques ne circulent jamais entre les - espaces, mais restent centralisées au niveau de la base de - données. - -Les commandes TUI suivantes nécessitent de travailler dans -l'environnement graphique: - -* ``visu``: afficher une carte de champ pour contrôle visuel rapide - (pas de paramettrage possible) - - >>> view(f) - - diff --git a/src/MEDOP/doc/sphinx/xmed-workingnotes-2010.rst b/src/MEDOP/doc/sphinx/xmed-workingnotes-2010.rst deleted file mode 100644 index 724c9a832..000000000 --- a/src/MEDOP/doc/sphinx/xmed-workingnotes-2010.rst +++ /dev/null @@ -1,461 +0,0 @@ -.. meta:: - :keywords: maillage, champ, manipulation - :author: Guillaume Boulant - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -ANNEXE: Note de travail concernant le chantier XMED 2010 -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -.. contents:: Sommaire - :local: - :backlinks: none - -Principes directeurs du développement -===================================== - -En matière de développement: - -* On ne cherche pas d'emblée à s'inscrire dans la fabrication d'un - module SALOME diffusable dans la version d'exploitation 2010 (SALOME - 6). La raison est double: (i) on souhaite au moins pour 2010 ne pas - devoir tenir compte des contraintes de temps SALOME et (ii) le - produit envisagé fin 2010 est une maquette qui cherche à éprouver - l'ergonomie générale d'utilisation et en aucun cas on ne peut - garantir la réalisation d'un module SALOME compatible avec les - exigences de mise en exploitation. -* On ne cherche pas d'emblée à capturer tous les cas d'application, - mais à concevoir un développement qui acceptera les extensions de - périmètres dans des conditions raisonnables. Aussi, les - fonctionnalités développées seront celles qui sont nécessaires à la - réalisation des cas d'application de référence; - -En matière d'ergonomie: - -* L'interface utilisateur de référence (appelé espace de travail dans - le volet de spécifications fonctionnelles) est l'interpréteur - python. Les fonctionnalités doivent être pensées pour un usage - adapté à une interface textuelle (TUI) de ce type. -* La création d'une interface graphique (GUI) peut être envisagée en - complément et comme un moyen de manipuler graphiquement les - fonctionnalités développées pour l'interface textuelle et pour aider - la préparation des variables dans l'interface python. -* Le modèle d'un processus de manipulation de champs est: - - - Préparation du jeu de variables U, V, ... représentant les champs - à manipuler. C'est à ce stade que l'on résoud la question de - sélection des données (dans un champ publié dans l'arbre d'étude, - par un module de calcul ou par chargement d'un fichier med) - - Utilisation des variables avec une sémantique la plus proche - possible du modèle conceptuel et des spécifications - fonctionnelles; - - Création des variables qui représentent les résultats des - fonctions de manipulation; - - Persistence (fichier med), visualisation (SALOME) ou export (vers - une structure qui peut être directement utilisable en numpy) - -Sur le plan technique: - -* On souhaite spécifier clairement le conteneur SALOME des fonctions - de manipulation de champs. Pour discussion: - - - Il apparaît que les modules SALOME MED et VISU contiennent déjà - des fonctions qui peuvent faire partie des fonctions de - manipulations de champs (en particulier pour l'exploration des - structures MED, leur visualisation et la sélection des données à - manipuler). - - Dans la mesure où le module MED n'est pas utilisé à ce jour (en - tout cas pas sous sa forme de module SALOME) et compte-tenu du - caractère obsolescent du module VISU (amené à être remplacé sur le - plan fonctionnel par le module PARAVIS), on pourrait examiner la - création d'un module dédié à la manipulation des maillages et des - champs par l'agrégation technique au sein d'un même module des - fonctions des modules MED et VISU. - -Au moins dans un premier temps, on se donne les limites suivantes: - -* Une opération ne peut pas combiner des pas de temps différents. Dans - l'hypothèse où cette limite venait à être levée, on doit spécifier - le pas de temps de la donnée résultat; -* Le domaine d'application d'une opération pourra être défini - exclusivement par la donnée d'un maillage ou un groupe d'éléments du - maillage; -* On ne traite pas le cas des champs qui prennent leurs valeurs aux - points de gauss ou aux noeuds par élément. Une particularité de ces - types de support est que le repérage de la position implique deux - indices (par exemple l'indice de la maille, puis l'indice du point - de gauss). - -Eléments de conception -====================== - -Plan général ------------- - -On peut par exemple imaginer une maquette du genre: - -* En C++ dans MEDGUI, charger un fichier med et donner une vue de la - structure des maillages et des champs dans l'arbre d'étude. -* Sélectionner un élément (par exemple un pas de temps d'un champ) et - le menu contextuel permet d'exporter ce champ dans la console python - pour manipulation. Pour cela, s'inspirer de la fonction - ``XCADGUI::OnLoadScript()`` du XCADGUI pour manoeuvrer un objet - PythonConsole. -* L'élément est marqué comme ayant été exporté, on peut imaginer une - récupération ultérieure. -* Exporter un deuxième champ cohérent avec le premier (même pas de - temps et défini sur le même maillage avec le même support, on - s'arrange pour). -* Dans la console python, faire les opérations sur les champs -* Publication du champ résultat dans l'arbre d'étude pour sauvegarde - ultérieure. C'est a priori le gros morceau qui consiste à faire un - objet CORBA MED à partir d'un objet MED standard, en plus défini - dans la console python (sous forme d'objet python). - -Quand ce premier cas d'utilisation est au point, on peut envisager de -le compléter par les opérations suivantes - -* exporter le résultat med dans un fichier -* visualiser les champs produits - -Plan de développement: - -* Faire une maquette en MEDMEM pur d'abord, car quelque soit le choix - d'architecture, l'opération physique se déroulera en définitif au - niveau de MEDMEM pur. -* Prévoir une implémentation des opérations sous forme de fonctions - informatiques, même les opérations algébriques (+,-,*,/). Pour ces - dernières et dans certaines conditions (quand on manipule - directement les strutures MEDMEM et non pas les objets CORBA), - l'utilisation des formes A+B, A-B, ... peuvent être rendues - possibles. Dans ce cas, voir la possibilité de combiner plusieurs - opérations algébriques sur une seule ligne: A+B-C*0.3. -* On peut charger la structure MED sous forme d'objet CORBA publiable - dans l'étude, de sorte d'avoir accés aux méta-données et pouvoir par - exemple sélectionner les champs d'intérêt. De cet objet CORBA, on ne - récupère que les informations nécessaires au chargement d'un champs: - le nom du champs, le nom de son maillage associé, les identifiants - du pas de temps, au besoin une structure Field non chargée (par - exemple pour récupérer plus facilement le maillage). -* Un mécanisme (à développer à partir du PyConsole par exemple) - pourrait alors permettre le chargement des champs sélectionnés dans - la console python et sous un nom facile à manoeuvrer. Prendre - inspiration sur XCADGUI::LoadIntoPythonConsole(). -* A priori, les données sont physiquement chargée dans le GUI. Au - besoin, il semble possible (cf. MED_i::init) de fabriquer une objet - CORBA field à partir d'un field standard (à tester). - -Une autre idée est de récupérer le pointeur CORBA MED dans la console -python et de tirer les données à partir de là. Ajouter une couche de -wrapping python pur pour gérer les cas de simplification (surcharge -des opérations arithmétiques par exemple). - -Besoins complémentaires: - -* L'interpréteur doit contenir des éléments d'aide (par exemple un - help qui liste les opérations possibles sur les champs chargés) -* prévoir quelques fonctions de visu et de persistence. Cela commence - probablement par des fonctions de publication dans l'étude des - champs créés par les opérations de manipulation. Les champs sont - physiquement ajouté automatiquement à la structure med par le MedOp - mais il n'est pas obligatoirement publié => fournir un moyen de - publication. - -Limitations actuelles (liées à la conception de MEDMEM): - -* les champs doivent être gérés par la même structure MED car ils - doivent partager le même support. -* les opérations possibles dans MEDMEM sont entre champs pris sur un - pas de temps (Q: les pas de temps peuvent-ils être différents). - - -Développements --------------- - -Développement de classes proxy: - -* FieldProxy, FieldTimeSeriesProxy -* Attention pour les éries temporelles, le SUPPORT med peut être - différent en chaque pas de temps (par exemple en cas d'extension - spatiale du champ au cours du temps). - -MEDMEM_MedDataManager: - -* FIX: test de l'implémentation C++ au travers de la fonction test() du - MedOperator ==> OK. Quand on fait la même opération depuis python - via l'interface SWIG ==> au deuxième appel de getFieldDouble, le - destructeur du champ semble être appelé. Pb de gestion des pointeurs? - - -Evolutions à prévoir -==================== - -Concernant MEDMEM: - -* FIX: SALOME_MED::MED::getField devrait pouvoir être appelée - plusieurs fois de suite puisqu'on recycle la référence si elle est - déjà chargée. -* IMP: MEDMEM::MED faire une gestion des chargements des champs (par - exemple avec un getField qui renvoie le champ s'il est déjà chargé - ou le charge et le renvoie sinon). -* IMP: Récupérer le nom du fichier med à partir de l'objet MED, en - passant a priori par le driver associé. Plusieurs driver peuvent - être associés à une structure MED car les données peuvent être - chargées en plusieurs fois et de plusieurs fichiers. Il faut donc - étendre la structure MED pour avoir accés à la liste des driver puis - de cette liste déduire les noms des fichiers. -* IMP: Opérations combinant des champs sur des support différents ne - peuvent pas être faites par l'API (une exception est levée en cas de - supports incompatibles), mais on peut imaginer le faire en - manoeuvrant les tableaux de données directement. -* INF: faire le point sur les fonctions utilitaires autour de MEDMEM - et de son interface SWIG (ex: dumpMEDMEM.py, med_opfield_test.py). -* IMP: dans MEDMEM::MED et SALOME_MED::MED, pouvoir enlever un champ - préalablement ajouté: une fonction removeField en complément de - addField. - -Concernant l'interface SALOME_MED: - -* IMP: Fonctions algébriques, qui seront implémentées au niveau de la - structure MED et requêtées au niveau des classes proxy en spécifiant - les identifiants des champs impliqués et les paramétres requis (pas - de temps en particulier). - -Concernant le module MED: - -* IMP: pourvoir exporter la structure med dans un fichier med (la - structure ayant pu être enrichie par la publication de champs créés - par les operations de champs. - - -Historique des travaux -====================== - -20100726 : mise au point du schéma de conception ------------------------------------------------- - -Choix entre MEDMEM et MEDCoupling: on reste sur MEDMEM pour plusieurs -raisons: - -* MED Coupling ne peut pas gérer des mailles de dimensions différentes - dans un même modèle (choix faits dans un soucis de performance dans - l'accès à une structure de donnée compact). On peut contourner le - problème en définissant deux champs pour traiter chacun des type de - mailles. -* Un champ repose sur un maillage complet (pas de notion de profil, - mais cela peut être émulé en créant deux maillages) -* Le concept de point de gauss n'existe pas (pas implémenté) - -TODO: - -* Idéalement, il conviendrait de faire un état des lieux du module - MED, en particulier des éléments MEDMEM (le coeur), les interfaces - CORBA associées (MED.idl implémenté dans le package source - MEDMEM_I), l'engine (composant SALOME d'interface MED_Gen.idl et - implémenté dans le package source MED) et le GUI (MedGUI.cxx - implémenté dans le package source MEDGUI). - -* Ergonomie TUI et modèle CORBA associé: - - 1. Charger un objet medmem (puis les objets métier mesh et field) - sur un domaine d'application donné. - 2. En faire des variables disponibles dans l'interface TUI et que - l'on peut manipuler dans des opérations algébriques. - 3. Pouvoir au besoin en faire des objets CORBA pour l'interface avec - les autres modules SALOME. - -* Compléter le diagramme de la structure informatique de MED (en - particulier l'implémentation des interface IDL). -* Préparer un module de travail XMED (organisation d'une bibliothèque) - -Tests à réaliser: - -* Est-il possible de faire des opérations algébriques à partir des - objets SALOMEMED (objects CORBA MED)? -* Création d'un objet MED_i à partir d'une objet MED pur préalablement - chargé en mémoire. - -A retenir: - -* Des opérations de champs sont possibles sur des champs à des pas de - temps fixés. Si l'opération doit être menée sur plusieurs pas de - temps, alors itérer sur chaque pas de temps. L'idée ici est - d'introduire le concept de série temporelle de champs en temps - qu'objet manipulable. -* Pour deux champs différents de la même structure MED, la données des - identifiants dt et it ne correspond pas forcément au même instant - absolu (en tout cas rien ne le garanti, même si c'est tout de même - une pratique courante). - -20101005 : première maquette de démonstration de l'ergonomie en MEDMEM pur --------------------------------------------------------------------------- - -XMED: svn révision 16 -Travailler avec le fichier de donnée testfield.med joint. - - -20101007 : Vers une maquette CORBA ----------------------------------- - -Le contexte d'utilisation des opérations de champs est l'environnement -SALOME. Le support de gestion des données est donc l'étude SALOME. Au -plus bas niveau, les champs sont des objets MEDMEM instanciés dans une -session SALOME (soit par un code de calcul intégré, soit par -chargement des données à partir d'un fichier med). Ces objets sont en -général référencés dans l'étude SALOME sous la forme d'objets CORBA de -classe SALOMEMED::FIELD. Plus exactement, l'étude SALOME gère des -SObject (Study Object) dont un attribut est une référence vers un -objet CORBA de classe SALOMEMED::FIELD qui lui-même encapsule un objet -MEDMEM::Field. - -On peut donc envisager une solution dans laquelle on donne à -l'utilisateur des poignées de manipulation des objets -SALOMEMED::FIELD, par exemple au moyen d'un modèle informatique de -type proxy. Cela signifie que l'utilisateur ne manipule pas -directement des objets MEDMEM mais des objets python qui font -l'interface (à concevoir et implémenter, a priori avec un design -pattern de type proxy). - -L'utilisation directe des objets MEDMEM aurait pu être une solution -extremement pratique dans la mesure où ces objets en l'état peuvent -être combinés dans des opérations de champs (c'est déjà -implémenté). Par contre, ce procédé souffre de limitations importantes -dans la gestion et la circulation des données pour les différents cas -d'utilisation envisagés (visualisation, export, transfert à un autre -module SALOME). - -L'avantage de la solution proposée est multiple: - -* Elle permet de travailler sur une structure MED cohérente pour - intégrer les résultats des opérations de calculs et combiner des - champs cohérents entre eux. Tout passe par des classes proxy qui - pourront s'assurer de la cohérence des opérations demandées et - exécuter automatiquement les fonctions de pré-traitement ou - post-traitement requises pour ces opérations. On peut imaginer par - exemple que les requêtes d'opération soient envoyées par les classes - proxy à la structure MED à laquelle les champs sont associés pour - piloter l'opération en MEDMEM pur. -* Elle permet d'automatiser un certain nombre d'opérations - implicites. Par exemple si deux champs ne sont pas définis dans la - même unité, un changement d'unité peut être effectué automatiquement - par la classe proxy avant de commander l'opération au niveau - MEDMEM. -* Elle permet de laisser les données sur le container SALOME et de - réaliser des opérations sans rappatrier les données en local (qui - peuvent être en trés grand nombre). -* Elle permet d'étendre facilement l'ergonomie de manipulation des - champs, par exemple en définissant la notion de *série temporelle de - champs*, ou encore les concepts de *domaine de définition* évoqués - dans les spécifications fonctionnelles. -* Elle rend immédiat la circulation des données entre modules SALOME, - puisque les champs restent accessble par des objets CORBA, en - particulier pour la visualisation ou l'export des champs produits - par les opérations. - -Elle a cependant des inconvénients et/ou limitations: - -* Elle nécessite l'implémentation d'une classe proxy pour encapsuler tous - les appels aux objets SALOME_MED (et donc MEDMEM). Cette interface - se limite a priori aux opérations de champs (les opérations - algébriques dans un premier temps). -* Les champs à manipuler dans une opération donnée doivent être gérés - par la même structure MED. - -Il est à noter également que les interfaces de programmation de -SALOMEMED (interface CORBA pour MEDMEM) devront être étendues pour -permettre des requêtes de manipulations de champs (fonctions addition, -soustraction, multiplication, ...). Pas de contrainte ici sur -l'ergonomie puisque la manipulation par l'utilisateur se fera au -niveau des classes proxy uniquement. - - -Hypothèses: - -* On tente ici une maquette qui exploite dans la mesure du possible le - fonctionnement actuel du module MED, en particulier la gestion des - données dans l'étude. -* Dans une deuxième version, on pourra examiner sérieusement la - révision de la gestion des données dans le module, quitte à la - spécifier et maquetter dans XMED pour intégration ultérieure dans - MED. Exemple: - - - Pouvoir gérer plusieurs structures med dans l'étude. - -* Enfin, on exploite MEDMEM en l'état. Pour les besoins de la gestion - des données (gestion des chargements des champs en particulier, - références croisées pour retrouver le med à partir du champ par - exemple, ...), il pourra être nécessaire de faire évoluer MEDMEM. Il - faut pouvoir par ailleurs gérer indifféremment une structure med (et - les champs qui y sont associés) qu'elle soit créée en mémoire from - scratch ou chargée d'un fichier (donc attention avec les opérations - de lecture read(), sur les maillages comme sur les champs). La - structure med permet d'obtenir les méta données (meta-field par - exemple) mais ne permet pas de savoir si les données sont - physiquement chargées ou pas. - - -Révisions: - -* XMED svn revision 21 + tarball MED_SRC-20101014-15h26m.tgz. - Première version qui permet d'importer un champ dans la console - python sous la forme d'un FieldProxy. Ne permet pas encore de faire - des opérations. Introduction dans le module MED de l'interface MEDOP - pour prendre en charge les opérations sur les champs. - - -20101019 : Maquette de démonstration pour l'addition ----------------------------------------------------- - -Cette maquette implémente une solution technique de bout en bout (de -l'interface python aux objets MEDMEM, en passant par le fieldproxy -puis les servants CORBA pour les operations, ...) mais sur le -périmètre de l'addition de champs sur tout leur domaine de définition -et pour un pas de temps donné. - -Limitations: - -* gére l'addition de champs de type double uniquement (parceque le - reste n'est pas implémenté) - -Révisions: - -* XMED: svn révision 25 -* MED: cvs tag BR_medop_20101019 - - -20101020: Fonctions complémentaires ------------------------------------ - -Cette version test la faisabilité des fonctions complémentaires pour -accompagner la manipulation de champs. Cela comprend en particulier: - -* **la sauvegarde des champs produits** dans un fichier med (un champ ou - toute la structure med). Pour cela, on définit un med proxy comme - l'extention du SALOME_MED::MED (prévir plutôt d'implémenter ce type - de fonction au niveau C++ pour permettre un usage au niveau du GUI - C++?). -* **la visualisation d'un champ** au moyen du module VISU. -* **des fonctions d'aide interactives** pour assister l'utilisateur - dans la console de manipulation des champs. - - -Questions: - -* peut-on sauvegarder un champ unique? -* peut-on faire en sorte que ce soit l'affectation à une variable qui - provoque l'ajout du champ à la structure med (ou plus exactement qui - supprime tous les champs intermédiaires). - - -Révision: - -* XMED: svn revision 31 -* MED: cvs tag BR_medop_20101025 - - -20110606: commit avant transfert dans git ------------------------------------------ - -* XMED: svn revision 53 - -Les parties de MED utiles à MEDOP seront reversées dans XMED -dans une première étape, puis le tout dans MED 6 au final. diff --git a/src/MEDOP/doc/sphinx/xmed-workingnotes-2011.rst b/src/MEDOP/doc/sphinx/xmed-workingnotes-2011.rst deleted file mode 100644 index 8ba8b8068..000000000 --- a/src/MEDOP/doc/sphinx/xmed-workingnotes-2011.rst +++ /dev/null @@ -1,473 +0,0 @@ -.. meta:: - :keywords: maillage, champ, manipulation - :author: Guillaume Boulant - -.. include:: xmed-definitions.rst - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -ANNEXE: Note de travail concernant le chantier XMED 2011 -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -.. contents:: Sommaire - :local: - :backlinks: none - -Cas d'utilisation métier -======================== - -On illustre par un exemple (Christophe Vallet, R&D/MMC, 1/7/2011):: - - J'ai souvent des fichiers med de résultats de calcul, et j'aimerais y - ajouter de nouveaux champs issus de champs existants. J'aimerais - aussi pouvoir créer de nouveaux meds plus petits par extraction de - certaines composantes de champs, certains groupes ou certains pas de - temps. - -On peut exprimer le besoin sous la forme des cas d'utilisation -suivants (use cases): - -* **UC1: combiner dans un même fichier med des champs issus de - plusieurs sources de données**. On peut par exemple charger un - premier fichier, puis ajouter à cette base des champs issus d'autre - fichiers ou générés par manipulation de champs, ou encore générés - par un module de calcul qui produirait directement du MEDCoupling. -* **UC2: créer un champ contenant certaines composantes d'un autre - champ**. On pense ici aux fonctions de restriction, qui permettraient - de récupérer certaines composantes uniquement. -* **UC3: créer un champ contenant certains pas de temps d'un autre - champ**. C'est un cas particulier des fonctions de restriction - évoquées ci-dessus. -* **UC4: créer un champ comme la limitation d'un autre champ à un - groupe de mailles**. C'est un cas particulier des fonctions de - restriction évoquées ci-dessus. Notion de domaine spatial. A - priori la notion de groupe est définie dans MEDLoader. - -On peut ajouter également les UC identifiés pour la maquette 2010: - -* **UC5: comparer des champs issus de source de données différentes**, - par exemple des champs chargés de deux fichiers med différents et - qui s'appuient sur le même maillage (au moins conceptuellement). Le - problème technique ici est de pouvoir changer le maillage d'un - champ, pour ramener tous les champs sur le même maillage (au sens - informatique). Ceci est une contrainte de MEDCoupling, les - opérations sur des champs A et B imposent que A et B soient définis - sur le même maillage, i.e. le même objet informatique. -* **UC6: créer un champ de toute pièce sur un maillage**, ou un groupe - de mailles. Ce cas d'usage est typiquement prévu pour produire les - conditions de chargement initial d'une structure. Il s'agit ici - d'initialiser un champ à partir de zéro sur une surface prédéfinie - de la géométrie (par exemple spécifiée par un nom de groupe de - mailles). - -Pour UC5: les sources de données sont référencées dans l'object -browser. On importe explicitement les données dans l'espace de -travail. On peut détecter que les maillages sont identiques et on -propose à l'utilisateur de transférer le champ sur le maillage déjà -présent. Sinon, les champs devront être référencés sur des maillages -distincts dans l'arbre de l'espace de travail. - -Analyses préliminaires pour le chantier 2011 -============================================ - -On fait le choix pour le chantier 2011 de travailler à partir de la -bibliothèque MEDCoupling (et non plus MEDMEM comme c'était le cas dans -le démonstrateur 2011). - -Analyse de MEDCoupling et MEDLoader ------------------------------------ - -MEDCoupling est l'implémentation du modèle de données MED (avec -recherche de minimisation des dépendances logicielles) et MEDLoader -fournit une ensemble de fonctions pour le chargement des structures -MEDCoupling depuis un fichier ou inversement leur sauvegarde sous -forme de fichiers. - -Dans l'implémentation MEDCoupling, un champ est l'ensemble des valeurs -d'une grandeur physique sur un maillage pour un pas de temps donné. Un -champ est caractérisé par: - -* un support spatial, le maillage -* un type de discrétisation spatial, défini par l'emplacement des - valeurs sur le maillage (sur les noeuds, sur les cellules, aux - points de gauss, ...) et le mode d'interpolation spatial (P0, P1, - etc) -* un pas de temps, défini par deux entiers (iteration, order) et un - réel (timestamps) - -Dans cette implémentation, il existe une association 1..n entre un -maillage et un champ (alors que dans MEDMEM, la structure -intermédiaire SUPPORT est implémentée). - -MEDCouplingCorba fournit un ensemble de servants CORBA pour manoeuvrer -des structures MEDCoupling au travers du bus CORBA. L'interface à ce -jour est délibérément réduite. Des classes dites "Cliente" sont -fournies pour piloter les servants CORBA depuis un contexte -client. Par exemple ``MEDCouplingFieldDoubleClient`` fournit une -fonction de création d'une structure MEDCoupling à partir d'un -pointeur vers un servant CORBA. La structure est créée localement -(dans le contexte client) avec duplication des données issue de la -structure encapsulée par le servant CORBA (récupération par la -fonction de sérialisation). - -Aucune interface CORBA n'est défini pour MEDLoader. - -Questions: - -* Voir comment sont créés les servants, et surtout comment ils sont - récupérés (via le lcc?) -* Comment peut-on définir un champ sur un groupe de mailles (et non - pas sur le maillage complet)? Comment peut-on extraire le champs - circoncit à une groupe de mailles pour des opérations. - - - R: méthode changeUnderlyingMesh - -* Comment manipuler deux champs chargées de fichiers différents mais - construit sur le même maillage (conceptuellement). On peut forcer la - réassociation d'un champ sur un autre maillage? -* Manipuler des champs de pas de temps différents? Différentes - composantes d'un ou plusieurs champs? -* Comment importer un MedCoupling dans PARAVIS? (dans VISU?)? - -* mapper sur une image - -Improvments: - -* MEDLoader::Write should raise an exception if the filepath is not writable -* MEDDataManager: développer une classe chapeau sur MEDCoupling et - MEDLoader pour aider au chargement et la gestion de données MED - (orienté manipulation de champs). Cette classe serait associée des - structures légères FieldHandler et MeshHandler et des listes - correspondantes pour la navigation dans les méta-données. -* Sur base du MEDDataManager, prévoir des ports med pour yacs par - lesquels pourrait transiter des handler. - -Nouveaux concepts à prendre en compte -------------------------------------- - -Au démarrage du chantier 2011, on observe que les concepts suivants -sont introduits dans le module MED: - -* Le conteneur MED n'existe plus, utiliser MEDFILEBROWSER pour charger - les fichiers med et obtenir les informations générales sur le - contenu. -* MEDFILEBROWSER: remplace le concept de driver et fournit les - fonctions précédemment fournies par la classe MED pour obtenir les - informations de structure. -* Concept d'Extractor pour une lecture sélective des données de champs - (suivant un critère d'extraction) -* Il n'est plus nécessaire d'appeler les méthodes read explicitement - sur les objets (MESH et FIELD) pour charger les données. Par - ailleurs, on peut définir deux fois le même champs (double - chargement a priori) sans lever d'exception). - - -Analyse de conception pour le chantier 2011 -=========================================== - -Composants SALOME (interfaces IDL) ----------------------------------- - -* MEDDataManager: défini une structure FIELD pour identifier un champ - dans les requêtes. Il s'occupe également de la récupération physique - des données, quelqu'en soit la source (fichier avec MEDLoader, autre - module SALOME comme PARAVIS avec une méthode à définir) -* MEDCalculator: s'occupe des requêtes de calcul dont les arguments sont - les structures FIELD du MEDDataManager. Reprendre l'interface de - MEDOP. - -Use case à réaliser depuis un client python: - -* UC01: ajouter un fichier d'entrée et accéder aux informations - concernant les champs. Ex: récupérer une structure champs par la - donnée des paramètres primaires (nom identifiant, dt, it, nom du - maillage). -* UC02: créer des champs et les ajouter au MEDDataManager -* UC03: mener des opérations basique sur les champs en console python - -Interface Utilisateur ---------------------- - -L'interface utilisateur est composée des parties suivantes: - -* une partie GUI (appelée par la suite MEDGUI) qui s'occupe de piloter - le chargement des données dans l'espace de travail, au moyen d'une - interface graphique; -* une partie TUI (appelée par la suite MEDTUI) qui s'occupe de piloter - la création de champs, au moyen de commandes exécutées dans la - console python. - -Le principe est que les champs sont préalablement chargés au niveau du -composant SALOME au moyen de l'interface graphique (MEDGUI), puis -manoeuvrés depuis l'application SALOME au moyen de variables proxy -définies dans la console python (MEDTUI). Au chargement, les champs -sont indéxés par le MEDDataManager, puis les index sont rendus -accessibles au niveau du GUI au moyen d'une représentation -arborescente de la structure MED. Les feuilles de l'arbre -correspondent à des champs qui peuvent être sélectionnés et dont -l'index peut être obtenu de la sélection. - -L'espace de travail est organisé autour du concept de -"workspace". L'étude SALOME liste les datasource (les fichiers source -des données med, mais peut-être aussi les référence vers des objets -MED déjà existants ou chargé dans PARAVIZ). Une vue complémentaire -permet de voir la structure fine d'une source de données. - -Concernant MEDGUI: - -* la représentation des données (les champs et les maillages associés) - doit permettre de récupérer par l'interface graphique les - identifiants des champs à manipuler (a priori les structures FIELD - définies par le composant MEDDataManager). Cela conduit à la mise en - place des composants suivants: - - - MedDataModel hérité de TreeData. Il est peuplé avec les - méta-données décrivant la structure MED explorée. - - MedGuiManager qui permet l'implantation du doc widget de - présentation - -TODO: - -* specifier le concept de workspace (qui a une entrée dans l'étude?) - en bijection avec un datamanager -* identifier des interlocuteur/utilisateur pour l'aspect ergonomie d'usage - -Concernant MEDTUI: - -* Il fournit les classes FieldProxy - -Questions: - -* Comment traiter le cas du travail sur des composantes ciblées, plus - généralement, comment introduire le concept de domaine - d'application? -* Prévoir des fonctions génériques (initialisation d'un champ sur un - maillage avec une fonction analytique de la position, sauvegarder - les champs créés dans un fichier med) - - -Tâches de développement -======================= - -T20110622.1: Gestion des données internes ------------------------------------------ - -**Status: terminé.** -Suite: fonction de sauvegarde au niveau graphique également - -On vise les cas d'utiliation suivants: - -* UC1: intégrer dans le datamodel du gui un champ créé dans la console - python (et donc présent dans le datamanager du composant). Définir - l'utilité? -* UC2: renommer un champ et plus généralement changer ses méta-données - (avec assurance de synchronisation entre toutes les données). -* UC3: sauvegarder une sélection de champs. La sélection peut se faire - dans l'arbre du datamodel gui. - -WARN: robustesse de fieldproxy - - - -T20110622.2: UC Initialisation/Création de champs -------------------------------------------------- - -**Status: à faire** - -Les cas implémentés à ce jour sont la création de champs à partir de -champs existants et chargés d'un fichier med. On souhaite ici réaliser -des cas 'utilisation autour de la création de champs "from scratch", -s'appuyant tout de même sur un maillage chargé. - -UC01: Sélection d'un groupe de maille dans SMESH pour initialiser un -champ (par exemple les conditions limites d'un problème de calcul). - -UC02: créer un champ avec des restrictions qui définissent le domaine -d'application des opération de champs. - -UC03: créer un champ à partir d'une image (codes rgb utilisé comme les -composantes du champs vectoriel ou niveaux de gris pour un champ -scalaire. Attention, pour ça, il faudra a priori fiare une projection -du maillage cartesien de l'image sur le maillage (quelconque) sur -lequel on souhaite définir le champ. - -UC04: créer un champ à partir d'un tableau numpy - -De manière générale, ce type de création sera assisté par le -MEDGUI. Au niveau MEDTUI, les fonctions pourraient être fastidieuses -pour l'utilisateur. - -Par exemple, prévoir un menu contextuel qui propose les opérations -possibles en fonction de la sélection (en plus de la fonction d'import -dans la console python). - -TODO: - -* développer les fonctions d'initialisation, par exemple au moyen - d'applyFunc et du mécanisme de callable? - -T20110622.3: documentation contextuel -------------------------------------- - -**Status: à faire** - -* Remettre toutes les commandes dans le même fichier (fusionner cmdtools - et fieldtools) -* Faire un modèle générique de command (classe de base -* Batir la doc des commandes sur cette base (lister toutes les - instances de type Command par exemple) - -T20110622.4: remontée des exception du composant MEDCalculator --------------------------------------------------------------- - -**Status: en cours, compléter la couverture** - -Pour des messages contextuel sur les erreurs de calcul (ex: division -par 0) - -* Poursuivre le travail fait sur getMedEventListener -* Protéger tous les appels au composants effectués depuis la console - python (prendre example sur la commande save) - -T20110624.1: gestion des données GUI ------------------------------------- - -**Status: à faire** - - - -Le workspace a une entrée dans l'obrowser. Sur cette entrée on peut: - -* supprimer: supprime tout les champs associés -* sauvegarder. Dans ce cas, on rappelle l'ensemble des champs pour - cocher ceux qu'on veut sauvegarder. - -Le gui data model est réservé aux opérations sur les champs et à -piloter leur import dans la console python. - -TODO: - -* Spécifier les concepts de workspace, database, et datasource, espace - de gestion, ... et les associations. Simplifier avec l'appuie de use - cases. -* Mécanisme de mise à jour du TreeView de XSALOME (aujourd'hui, seul - l'ajout addChild est implémenté -* Clic droit sur objets de l'arbre: dans la notification TreeView -> - WorkspaceController, faire remonter l'évènement clic droit ainsi que la - liste des éléments sélectionné pour faire générer le menu contextuel - au niveau du WorkspaceController qui peut déterminer le contexte métier - (le TreeView ne le connaît pas). -* Définir des DataObject pour les maillages, les séries temporelles et - les champs - - -Spécification des espaces de données: - -* MEDDataManager dépend de l'étude (pour permettre la publication - d'information dans une étude SALOME). -* créer "sourcid = MEDDataManager::addDataSource(filename)", suivie de - requetes getFields(sourceid), getMeshes(sourceid) -* les espaces de données: dataspace, workspace. Un seul workspace par - étude, mais autand de datasources que l'on souhaite dans le - dataspace. Les datasources sont rangés dans l'étude (le dataspace) - et sont non modifiables après chargement (référence des sources de - données). - - -T20110628.1: extention à d'autres objets SALOME ------------------------------------------------ - -**Status: suspendu** - -On doit reposer la question de l'existance de l'arbre indépendant -(DockWidget), d'une part, et l'extention aux autres objets (GEOM et -SMESH en particulier) du principe de sélection graphique pour -utilisation dans la console python, d'autre part. - - -T20110628.2: visualisation d'un champ avec PARAVIS --------------------------------------------------- - -**Status: terminé (pour une première version)** -Suite: de nombreux défauts subsistent - -Questions/remarques: - -* Pb au démarrage du module: VisTrails fails to start -* Peux-t-on piloter la vue 3D sans charger le module? (voir - myparavis.py) -* Comment donner un nom au MEDReader1 dans l'arbre Pipeline? -* Comment utiliser directement les objets MEDCouplingField? - - -T20110706.1: documentation du module ------------------------------------- - -**Status: en cours (10%)** - -Documenter les commandes TUI puis l'utilisation générale de -l'interafce graphique. Mentionner l'existance de la commande medop.sh -pour travailler exclusivement en mode texte (utile pour les tests -rapides). - -Documenter les modalités d'exécution des tests. - -T20110708.1: helper python pour MEDCoupling -------------------------------------------- - -**Status: en attente (pas urgent)** - -Faire un helper python dans le package xmed qui permet de faire du -medcoupling facilement (essentiellement pour simplifier le chargement, -puis la sélection des données). Cela demanderait de faire un -MedDataManager comme une class C++ pure (non CORBA). Cette classe -travaillerait par exemple uniquement avec des id et des liste d'id, et -fournirait des fonctions d'affichage (comme le ``ls`` et le ``la``) -pour obtenir des meta-information. - -Le servant MedDataManager pourrait être une surcouche de cette classe -c++ pure. - -T20110708.2: analyses et tests ------------------------------- - -TODO: - -* créer un fichier de test avec plusieurs pas de temps -* créer un fichier de test avec des groupes de mailles - - -T20110728.1: refactoring MEDDataManager ---------------------------------------- - -Refactoring pour une meilleur association entre FieldHandler et MeshHandler: - -* dans la mesure du possible utiliser les id plutôt que les handler en - arguments des fonctions d'appel des objets -* A chaque champ (FieldHandler), on doit associer un meshid (et de - manière optionnelle un fieldseriesId, si le champ peut être associé - à une serie temporelle. A priori faisable uniquement au chargement - du datasource). -* Pour cela, revoir les fonctions internes newFieldHandler et addField - ou prévoir de les compléter à chaque fois qu'elles sont appelée avec - les informations concernant le meshid. -* addField est utilisée par le MEDCalculator -* Attention au raffraichissement des données handler au niveau du - Workspace. Peut-être le mieux est que les fieldproxy contiennent - uniquement le fieldid, et qu'ils interroge le datamanager à chaque - fois qu'ils ont besoin d'une donnée. Voir aussi les notifications - via le MEDEventListener? **Le plus simple est de faire la mise à - jour lors de l'appel à la méthode __repr__ du fieldproxy, i.e. quand - on essaye d'afficher les données**. Parceque sinon il n'y a pas de - problème puisque que le calculateur travaille à partir des id. - - -Petites améliorations du DataspaceController: - -* Au OnUseInWorkspace, stocker (dans la mesure du possible) le nom de - l'alias python dans un attribut du sobject. -* Dans DlgChangeUnderLyingMesh, expliquer que le champs sera dupliquer - est posé dans le WS. On peut donc proposer en option de lui associer - un alias pour manipulation dans la console - - - diff --git a/src/MEDOP/doc/sphinx/xmed-workingnotes-2012.rst b/src/MEDOP/doc/sphinx/xmed-workingnotes-2012.rst deleted file mode 100644 index 011190ef4..000000000 --- a/src/MEDOP/doc/sphinx/xmed-workingnotes-2012.rst +++ /dev/null @@ -1,84 +0,0 @@ -.. meta:: - :keywords: maillage, champ, manipulation - :author: Guillaume Boulant - -.. include:: xmed-definitions.rst - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -ANNEXE: Note de travail concernant le chantier XMED 2012 -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -.. contents:: Sommaire - :local: - :backlinks: none - - -Analyse preliminaire pour le chantier 2012 -========================================== - -La figure imposée pour le chantier 2012 est l'intégration du nouveau -module de manipulation de champs dans SALOME 6.6 (objectif CEA), en -préparation de la mise en exploitation dans SALOME 7 (objectif EDF). - -L'état actuel est: - -* Un module SALOME de nom MED intégrant les bibliothèques MEDCoupling, - MEDLoader, REMAPPER, mais aussi plusieurs packages logiciels - aujourd'hui obsolètes ou amener à disparaître pour l'échéance - SALOME7 -* Un module SALOME de nom XMED qui fournit les fonctions graphiques - pour la manipulation de champs. -* Ce module XMED utilise le module VISU pour les vue de contrôle. - -La cible est: - -* Un module unique (nom à définir, par exemple MEDOP) débarrassé des - packages logiciels obsolètes et intégrant les fonctions graphiques - (GUI et TUI). -* L'utilisation du module PARAVIS (au lieu de VISU) pour les vues de - contrôle. -* L'intégration de MEDCoupling avec YACS (port MED dans YACS par - exemple). - -A examiner: - -* voir les attendus concernant les ports MED dans YACS -* interface PARAVIS: utilisation du viewer (et de l'API python) sans chargement du GUI - -Tâches de développement -======================= - -20120904: Migrer XMED dans MED ------------------------------- - -Plan de travail: - -* Migration des composants + test - - - -20120904: Nettoyage de XSALOME ------------------------------- - -:status: en cours - -* Supprimer les vieilleries de XSALOME: - - - StdHelper -> Basic_Utils (KERNEL) - -20120829: mise en place du chantier 2012 ----------------------------------------- - -:status: terminé - -L'objectif de cette première étape est de reverser le prototype 2011 -(module XMED indépendant) dans la branche V6_main du module MED. On -peut procéder de la manière suivante: - -* update de XMED (et XSALOME utilisé par XMED) pour fonctionnement sur - V6_main -* Eliminer la dépendance à XSALOME -* Supprimer la gestion des multiversion SALOME5/6 au niveau de l'engine - -.. warning:: TODO: refaire le point sur les tâches initiées en 2011 -