From ef9db08c815361b806e558b78acf445adc43613d Mon Sep 17 00:00:00 2001 From: Anthony Geay Date: Wed, 23 Jun 2021 07:59:19 +0200 Subject: [PATCH] MEDCoupling Memory output from SMESH engine now deal with fields too. --- .../basic_smesh_output_with_mc_field.py | 175 ++++++++++++++++++ doc/salome/examples/tests.set | 1 + src/DriverMED/DriverMED_W_Field.cxx | 59 ++++-- src/DriverMED/DriverMED_W_Field.h | 19 +- src/MEDWrapper/MED_TFile.hxx | 3 +- src/MEDWrapper/MED_Wrapper.cxx | 8 +- src/SMESH_I/SMESH_Mesh_i.cxx | 15 +- src/SMESH_SWIG/smeshBuilder.py | 5 +- 8 files changed, 261 insertions(+), 24 deletions(-) create mode 100644 doc/salome/examples/basic_smesh_output_with_mc_field.py diff --git a/doc/salome/examples/basic_smesh_output_with_mc_field.py b/doc/salome/examples/basic_smesh_output_with_mc_field.py new file mode 100644 index 000000000..f900b96c2 --- /dev/null +++ b/doc/salome/examples/basic_smesh_output_with_mc_field.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python + +import sys +import salome + +import unittest + +class SMESHExportOfFieldsInMemory(unittest.TestCase): + + def testMEDCouplingFieldOnCells(self): + """ + Test focuses on ExportMEDCoupling method in the context of MED_CELL field output. + """ + salome.standalone() + salome.salome_init() + ### + ### SHAPER component + ### + + from salome.shaper import model + + model.begin() + partSet = model.moduleDocument() + + ### Create Part + Part_1 = model.addPart(partSet) + Part_1_doc = Part_1.document() + + ### Create Box + Box_1 = model.addBox(Part_1_doc, 10, 10, 10) + + ### Create Plane + Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOY"), 5, False) + + ### Create Plane + Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), 5, False) + + ### Create Partition + Partition_1_objects = [model.selection("FACE", "Plane_1"), + model.selection("FACE", "Plane_2"), + model.selection("SOLID", "Box_1_1")] + Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects, keepSubResults = True) + + ### Create Field + Field_1_objects = [model.selection("SOLID", "Partition_1_1_2"), + model.selection("SOLID", "Partition_1_1_4"), + model.selection("SOLID", "Partition_1_1_1"), + model.selection("SOLID", "Partition_1_1_3")] + Field_1 = model.addField(Part_1_doc, 1, "DOUBLE", 1, ["Comp 1"], Field_1_objects) + Field_1.addStep(0, 0, [[0], [1], [2], [3], [4]]) + + + model.end() + + ### + ### SHAPERSTUDY component + ### + + model.publishToShaperStudy() + import SHAPERSTUDY + Partition_1_1, Field_1_1 = SHAPERSTUDY.shape(model.featureStringId(Partition_1)) + ### + ### SMESH component + ### + + import SMESH, SALOMEDS + from salome.smesh import smeshBuilder + + smesh = smeshBuilder.New() + #smesh.SetEnablePublish( False ) # Set to False to avoid publish in study if not needed or in some particular situations: + # multiples meshes built in parallel, complex and numerous mesh edition (performance) + + Mesh_1 = smesh.Mesh(Partition_1_1) + Regular_1D = Mesh_1.Segment() + Local_Length_1 = Regular_1D.LocalLength(5,None,1e-07) + Quadrangle_2D = Mesh_1.Quadrangle(algo=smeshBuilder.QUADRANGLE) + Hexa_3D = Mesh_1.Hexahedron(algo=smeshBuilder.Hexa) + isDone = Mesh_1.Compute() + smesh.SetName(Mesh_1, 'Mesh_1') + + #### Mesh_1.ExportMED( r'Mesh_with_one_field_on_cells.med', 0, 41, 1, Mesh_1.GetMesh(), 1, [ Field_1_1 ], '',-1 ) + mfd = Mesh_1.ExportMEDCoupling(0, Mesh_1.GetMesh(), 1, [ Field_1_1 ], '',-1 )#### <- important line of test is here ! + + self.assertEqual(len(mfd.getMeshes()),1) + self.assertEqual(len(mfd.getFields()),1) + f = mfd.getFields()[0][0].field(mfd.getMeshes()[0]) + f.checkConsistencyLight() + import medcoupling + self.assertEqual(f.getDiscretization().getEnum(),medcoupling.ON_CELLS) + self.assertTrue(f.getMesh().getNumberOfCells()>1) + pass + + + def testMEDCouplingFieldOnNodes(self): + """ + Test focuses on ExportMEDCoupling method in the context of MED_NODES field output. + """ + salome.standalone() + salome.salome_init() + + ### + ### SHAPER component + ### + + from salome.shaper import model + + model.begin() + partSet = model.moduleDocument() + + ### Create Part + Part_1 = model.addPart(partSet) + Part_1_doc = Part_1.document() + + ### Create Box + Box_1 = model.addBox(Part_1_doc, 10, 10, 10) + + ### Create Plane + Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOY"), 5, False) + + ### Create Plane + Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), 5, False) + + ### Create Partition + Partition_1_objects = [model.selection("FACE", "Plane_1"), + model.selection("FACE", "Plane_2"), + model.selection("SOLID", "Box_1_1")] + Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects, keepSubResults = True) + + ### Create Field + Field_2_objects = [model.selection("VERTEX", "[Partition_1_1_2/Modified_Face&Box_1_1/Back][Partition_1_1_2/Modified_Face&Box_1_1/Left][Partition_1_1_2/Modified_Face&Box_1_1/Top]"), + model.selection("VERTEX", "Partition_1_1_2/Generated_Vertex&Plane_2/Plane_2&new_weak_name_1"), + model.selection("VERTEX", "[Partition_1_1_4/Modified_Face&Box_1_1/Front][Partition_1_1_4/Modified_Face&Box_1_1/Left][Partition_1_1_4/Modified_Face&Box_1_1/Top]"), + model.selection("VERTEX", "Partition_1_1_1/Generated_Vertex&Plane_1/Plane_1&new_weak_name_1"), + model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Left][Partition_1_1_1/Modified_Face&Plane_1/Plane_1][Partition_1_1_1/Modified_Face&Plane_2/Plane_2]"), + model.selection("VERTEX", "Partition_1_1_3/Generated_Vertex&Plane_1/Plane_1&new_weak_name_1"), + model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Partition_1_1_1/Modified_Face&Box_1_1/Left][Partition_1_1_1/Modified_Face&Box_1_1/Bottom]"), + model.selection("VERTEX", "Partition_1_1_1/Generated_Vertex&Plane_2/Plane_2&new_weak_name_1"), + model.selection("VERTEX", "[Partition_1_1_3/Modified_Face&Box_1_1/Left][Partition_1_1_3/Modified_Face&Box_1_1/Bottom][Partition_1_1_3/Modified_Face&Box_1_1/Front]")] + Field_2 = model.addField(Part_1_doc, 1, "DOUBLE", 1, ["Comp 1"], Field_2_objects) + Field_2.addStep(0, 0, [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9]]) + + model.end() + + ### + ### SHAPERSTUDY component + ### + + model.publishToShaperStudy() + import SHAPERSTUDY + Partition_1_1, Field_2_1 = SHAPERSTUDY.shape(model.featureStringId(Partition_1)) + ### + ### SMESH component + ### + + import SMESH, SALOMEDS + from salome.smesh import smeshBuilder + + smesh = smeshBuilder.New() + #smesh.SetEnablePublish( False ) # Set to False to avoid publish in study if not needed or in some particular situations: + # multiples meshes built in parallel, complex and numerous mesh edition (performance) + + Mesh_1 = smesh.Mesh(Partition_1_1) + Regular_1D = Mesh_1.Segment() + Local_Length_1 = Regular_1D.LocalLength(5,None,1e-07) + Quadrangle_2D = Mesh_1.Quadrangle(algo=smeshBuilder.QUADRANGLE) + Hexa_3D = Mesh_1.Hexahedron(algo=smeshBuilder.Hexa) + isDone = Mesh_1.Compute() + smesh.SetName(Mesh_1, 'Mesh_1') + + # 23th of june 2021 : Bug both in ExportMED and in ExportMEDCoupling + #Mesh_1.ExportMED( r'/tmp/Mesh_with_one_field_on_nodes.med', 0, 41, 1, Mesh_1.GetMesh(), 1, [ Field_2_1 ], '',-1 ) + #mfd = Mesh_1.ExportMEDCoupling(0,Mesh_1.GetMesh(), 1, [ Field_2_1 ], '',-1) + +if __name__ == '__main__': + unittest.main() diff --git a/doc/salome/examples/tests.set b/doc/salome/examples/tests.set index e0293d388..d674d6471 100644 --- a/doc/salome/examples/tests.set +++ b/doc/salome/examples/tests.set @@ -197,6 +197,7 @@ set(SESSION_FREE_TESTS basic_geom_smesh_without_session.py basic_shaper_smesh_without_session.py shaper_smesh_groups_without_session.py + basic_smesh_output_with_mc_field.py ) SET(EXAMPLES_TESTS ${BAD_TESTS} ${GOOD_TESTS} ${SESSION_FREE_TESTS} testme.py) diff --git a/src/DriverMED/DriverMED_W_Field.cxx b/src/DriverMED/DriverMED_W_Field.cxx index 041d1e8dd..c722aaf35 100644 --- a/src/DriverMED/DriverMED_W_Field.cxx +++ b/src/DriverMED/DriverMED_W_Field.cxx @@ -26,6 +26,7 @@ #include "DriverMED_W_Field.h" +#include "MED_TFile.hxx" #include "DriverMED.hxx" #include "DriverMED_W_SMESHDS_Mesh.h" #include "MED_Factory.hxx" @@ -236,16 +237,8 @@ SMDS_ElemIteratorPtr DriverMED_W_Field::GetOrderedElems() return SMDS_ElemIteratorPtr( new TItIterator( iterVec )); } -//================================================================================ -/*! - * Writes a field to the file - */ -//================================================================================ - -Driver_Mesh::Status DriverMED_W_Field::Perform() +Driver_Mesh::Status DriverMED_W_Field::PerformInternal(MED::PWrapper& medFile) { - if ( myFile.empty() ) - return addMessage("File name not set", /*isFatal=*/true ); // 'fatal' means 'bug' if ( myMeshId < 0 && myMeshName.empty() ) return addMessage("Mesh in file not specified", /*isFatal=*/true ); if ( _nbElemsByGeom.size() < 2 ) @@ -253,11 +246,6 @@ Driver_Mesh::Status DriverMED_W_Field::Perform() if ( !myMesh ) return addMessage("Supporting mesh not set", /*isFatal=*/true ); - int version = -1, major, minor, release; - if ( MED::GetMEDVersion( myFile, major, minor, release )) - version = major * 10 + minor; - - MED::PWrapper medFile = MED::CrWrapperW( myFile, version ); MED::PMeshInfo meshInfo; if ( myMeshId > 0 ) { @@ -361,6 +349,49 @@ Driver_Mesh::Status DriverMED_W_Field::Perform() return DRS_OK; } +/*! + * Writes a field to the file + */ +Driver_Mesh::Status DriverMED_W_Field::Perform() +{ + if ( myFile.empty() ) + return addMessage("File name not set", /*isFatal=*/true ); // 'fatal' means 'bug' + int version = -1, major, minor, release; + if ( MED::GetMEDVersion( myFile, major, minor, release )) + version = major * 10 + minor; + + MED::PWrapper medFile = MED::CrWrapperW( myFile, version ); + return this->PerformInternal(medFile); +} + +/*! + * Writes a field to a chunck of memory + */ +Driver_Mesh::Status DriverMED_W_Field_Mem::Perform() +{ + void *ptr(nullptr); + std::size_t sz(0); + Driver_Mesh::Status status = Driver_Mesh::DRS_OK; + bool isClosed(false); + MED::TMemFile *tfileInst = nullptr; + char *initPtr(_data->getPointer()); + mcIdType initSz(_data->getNumberOfTuples()); + _data->accessToMemArray().setSpecificDeallocator(nullptr); + _data->useArray(nullptr,false,MEDCoupling::DeallocType::C_DEALLOC,0,1); + {// let braces to flush (call of MED::PWrapper myMed destructor) + tfileInst = new MED::TMemFile(initPtr,initSz,&isClosed); + MED::PWrapper myMed = MED::CrWrapperW(myFile, -1, tfileInst); + status = this->PerformInternal(myMed); + } + if(tfileInst) + { + ptr = tfileInst->getData(); sz = tfileInst->getSize(); + } + _data = MEDCoupling::DataArrayByte::New(); + _data->useArray(reinterpret_cast(ptr),true,MEDCoupling::DeallocType::C_DEALLOC,sz,1); + return status; +} + namespace DriverMED // Implementation of functions declared in DriverMED.hxx { //================================================================================ diff --git a/src/DriverMED/DriverMED_W_Field.h b/src/DriverMED/DriverMED_W_Field.h index 03168e7cb..d34382371 100644 --- a/src/DriverMED/DriverMED_W_Field.h +++ b/src/DriverMED/DriverMED_W_Field.h @@ -31,6 +31,7 @@ #include "Driver_SMESHDS_Mesh.h" #include "SMDSAbs_ElementType.hxx" #include "SMDS_ElemIterator.hxx" +#include "MED_Common.hxx" #include #include @@ -64,8 +65,12 @@ class MESHDRIVERMED_EXPORT DriverMED_W_Field: public Driver_SMESHDS_Mesh /* * Add one field to the file */ - virtual Status Perform(); + Status Perform() override; + protected: + + Status PerformInternal(MED::PWrapper& medFile); + private: std::string _fieldName; @@ -80,4 +85,16 @@ class MESHDRIVERMED_EXPORT DriverMED_W_Field: public Driver_SMESHDS_Mesh std::vector< std::pair< SMDSAbs_EntityType, int > > _nbElemsByGeom; }; +#include "MEDCouplingMemArray.hxx" + +class MESHDRIVERMED_EXPORT DriverMED_W_Field_Mem : public DriverMED_W_Field +{ +public: + DriverMED_W_Field_Mem(MEDCoupling::MCAuto data):_data(data) { } + Status Perform() override; + MEDCoupling::MCAuto getData() const { return _data; } +private: + MEDCoupling::MCAuto _data; +}; + #endif diff --git a/src/MEDWrapper/MED_TFile.hxx b/src/MEDWrapper/MED_TFile.hxx index f30dc7a4b..70a5402cc 100644 --- a/src/MEDWrapper/MED_TFile.hxx +++ b/src/MEDWrapper/MED_TFile.hxx @@ -73,7 +73,8 @@ namespace MED class MEDWRAPPER_EXPORT TMemFile : public MEDIDTHoder { public: - TMemFile(bool* isClosedStatus = nullptr):MEDIDTHoder(isClosedStatus) { } + TMemFile(bool* isClosedStatus = nullptr):MEDIDTHoder(isClosedStatus) { memfile.app_image_ptr=nullptr; memfile.app_image_size=0; } + TMemFile(void *data, std::size_t sz, bool* isClosedStatus):MEDIDTHoder(isClosedStatus) { memfile.app_image_ptr=data; memfile.app_image_size=sz; } void Open(EModeAcces theMode, TErr* theErr = nullptr) override; void *getData() const { return memfile.app_image_ptr; } std::size_t getSize() const { return memfile.app_image_size; } diff --git a/src/MEDWrapper/MED_Wrapper.cxx b/src/MEDWrapper/MED_Wrapper.cxx index 4d0f99271..ad18d170c 100644 --- a/src/MEDWrapper/MED_Wrapper.cxx +++ b/src/MEDWrapper/MED_Wrapper.cxx @@ -90,10 +90,10 @@ namespace MED if (this->myCount++ == 0) { std::string dftFileName = MEDCoupling::MEDFileWritableStandAlone::GenerateUniqueDftFileNameInMem(); - memfile = MED_MEMFILE_INIT; - memfile.app_image_ptr=0; - memfile.app_image_size=0; - myFid = MEDmemFileOpen(dftFileName.c_str(),&memfile,MED_FALSE,MED_ACC_CREAT); + med_access_mode modeTmp(MED_ACC_CREAT); + if(memfile.app_image_ptr) + modeTmp = med_access_mode(theMode); + myFid = MEDmemFileOpen(dftFileName.c_str(),&memfile,MED_FALSE,modeTmp); } if (theErr) *theErr = TErr(myFid); diff --git a/src/SMESH_I/SMESH_Mesh_i.cxx b/src/SMESH_I/SMESH_Mesh_i.cxx index 4e442a7a0..afc798f24 100644 --- a/src/SMESH_I/SMESH_Mesh_i.cxx +++ b/src/SMESH_I/SMESH_Mesh_i.cxx @@ -4069,7 +4069,11 @@ public: void prepareForWriting(SMESH_Mesh_i& self) { /* nothing here */ } void exportField(SMESH_Mesh_i& self, const std::string& aMeshName, bool have0dField, SMESHDS_Mesh *meshDS, const GEOM::ListOfFields& fields, const char*geomAssocFields) { - THROW_IK_EXCEPTION("exportField Not implemented yet for full memory !"); + DriverMED_W_Field_Mem fieldWriter(_res); + fieldWriter.SetMeshName( aMeshName ); + fieldWriter.AddODOnVertices( have0dField ); + self.exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields ); + _res = fieldWriter.getData(); } public: MEDCoupling::MCAuto getData() { return _res; } @@ -4084,10 +4088,15 @@ CORBA::LongLong SMESH_Mesh_i::ExportPartToMEDCoupling(SMESH::SMESH_IDSource_ptr const char* geomAssocFields, CORBA::Double ZTolerance) { + MEDCoupling::MCAuto data; + SMESH_TRY; + if( !this->_gen_i->isSSLMode() ) + SMESH::throwCorbaException("SMESH_Mesh_i::ExportPartToMEDCoupling : only for embedded mode !"); MEDFileMemSpeCls spe; this->ExportPartToMEDCommon(spe,meshPart,auto_groups,autoDimension,fields,geomAssocFields,ZTolerance); - MEDCoupling::MCAuto res( spe.getData() ); - MEDCoupling::DataArrayByte *ret(res.retn()); + data = spe.getData(); + SMESH_CATCH( SMESH::throwCorbaException ); + MEDCoupling::DataArrayByte *ret(data.retn()); return reinterpret_cast(ret); } diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index e65c35749..43e8f431b 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -2355,7 +2355,10 @@ class Mesh(metaclass = MeshMeta): z_tolerance,Parameters,hasVars = ParseParameters(z_tolerance) self.mesh.SetParameters(Parameters) - return self.mesh.ExportPartToMEDCoupling(meshPart, auto_groups, autoDimension, fields, geomAssocFields, z_tolerance) + intPtr = self.mesh.ExportPartToMEDCoupling(meshPart, auto_groups, autoDimension, fields, geomAssocFields, z_tolerance) + import medcoupling + dab = medcoupling.FromPyIntPtrToDataArrayByte(intPtr) + return medcoupling.MEDFileData.New(dab) else: intPtr = self.mesh.ExportMEDCoupling(auto_groups, autoDimension) import medcoupling -- 2.30.2