From 2d790981e5d5175a92396df9b84c8bf1817b12d3 Mon Sep 17 00:00:00 2001 From: Anida Khizar Date: Wed, 11 Jan 2023 15:48:19 +0100 Subject: [PATCH] [Partial load] Implementation of a partial parallel load (of mesh and field) from a user-defined partition --- resources/CMakeLists.txt | 3 + resources/SimpleTest2D.med | Bin 0 -> 22464 bytes resources/SimpleTest3D.med | Bin 0 -> 16098 bytes resources/Test2DMultiGeoType.med | Bin 0 -> 8678 bytes src/MEDLoader/MEDFileField1TS.cxx | 306 +++++++-------- src/MEDLoader/MEDFileField1TS.hxx | 7 + src/MEDLoader/MEDFileFieldInternal.cxx | 103 ++--- src/MEDLoader/MEDFileFieldInternal.hxx | 2 + src/MEDLoader/MEDFileMesh.cxx | 44 +++ src/MEDLoader/MEDFileMesh.hxx | 3 + src/MEDLoader/MEDFileMeshElt.cxx | 107 ++++-- src/MEDLoader/MEDFileMeshElt.hxx | 10 +- src/MEDLoader/MEDFileMeshLL.cxx | 203 ++++++++-- src/MEDLoader/MEDFileMeshLL.hxx | 11 +- src/MEDLoader/MEDFilterEntity.hxx | 119 ++++++ src/ParaMEDLoader/ParaMEDFileMesh.cxx | 171 ++++++++- src/ParaMEDLoader/ParaMEDFileMesh.hxx | 20 + src/ParaMEDMEMTest/CMakeLists.txt | 2 + src/ParaMEDMEMTest/ParaMEDMEMTest.hxx | 13 + .../ParaMEDMEMTest_MEDLoader.cxx | 354 +++++++++++++++++- 20 files changed, 1180 insertions(+), 298 deletions(-) create mode 100644 resources/SimpleTest2D.med create mode 100644 resources/SimpleTest3D.med create mode 100644 resources/Test2DMultiGeoType.med create mode 100644 src/MEDLoader/MEDFilterEntity.hxx diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 85482604e..6a3a63e72 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -39,6 +39,9 @@ SET(MED_other_FILES Test2Dpoly.med Test3D.med Test3Dpoly.med + SimpleTest2D.med + SimpleTest3D.med + Test2DMultiGeoType.med UnitTetraDegenT.med DegenEdgeXY.med DegenFaceXYZ.med diff --git a/resources/SimpleTest2D.med b/resources/SimpleTest2D.med new file mode 100644 index 0000000000000000000000000000000000000000..3c890eba6fe0847b7e0893d3d1a4c751472cf3e1 GIT binary patch literal 22464 zcmeHP4Qv$06`nhDwtF0g5CZ`kbNn>WBm~=-AKOs-d_Vrd-m~w{6b!{UviT{tL*t;B ziqa$%Z3*;;mZnkC#!{poHXDa3BR40H*em&ncaEwzBzVR1w!N8)7;MNY)0t{rhzZZl6DW*H8LkRM zoZj2FO>Ncw>vm2A9%@L`?PLzdGN&<4##bw$aJ0EHs01Uv+Ff>eUG_HeO4+>n#jf&)%ARVu?$|}fyz2x z4V%DiBF$3HoV+()ERvqFS}`!U<(g_m1J60_GDow%DEWnNApUQ-E zB32vX{oV_lK6sxQ>pfTOVi{0SA`5=r(Bxu=pn$*Kz!3}n#>1WkX;@Iv)se?aH3dsH z9*wXbDBxc%Xj1-<856=jp+m{&emUXV_o0 z!hG*SheHVm*Wkk0_|Dp1^99Bnj$Cd;hr^MFT@lU5WezigyRw2wMUWplkV93^hq z^a4sSAE$nDDvXoE_kWRejFyvAfi13zJn=+*yI#QSWio#n>3O6VkP`Pu^O4+Sl=K;n zlAg&ay)@|9sJo&IyUs$2%ZK3tW;oHfoyA|iL^frL z$=cBpLoqh7Enr)~wt#JcQEmb7r91`F+sqc;W~i2dYYhiB*evUUfo3J#TptOCs%wMI z)k-WFQGB&}kJHLmNpNbS2G^8k!1=moXZqe|Lu1iiJQAefg;^=gXpd#=8P}Ox!9wN| z(c7%^Rlkg0Y`gn!8`2+w5)RDZE-57Q4#8nAog_I9NfM8-)m_3G)mIT5uHx?f!#TiS zltnbd!yMYEnbGmRmHZSuE|}}9n|j5>@g*-y$7ne>HK^){kV_kDJ{*}BpfVUXtm{`% z$CL+`z-W9^=xo-v^kD^SYrSKD2n3FHvz>r~myS<6zEXp=dP7C{F6&fk~%0WT?yBTK4xO?-eHo!P=wx%N_E;TSBjSNu+Nq)g^P*{ii*9lZEfDVmb<-$1>S=E zl7fXL1&h6f`GpI;i;ET(7R2Ejt2mxIjmoOz5jV1xO-G{z%)fBfSe*RmZrI$`-Wu*y z?rLr8dJ2)sOkI_~t-ZagpTiR(%}T|*<(aL=gh~c1F6NM5U3G(>A?1~MC2d2R_|^Rt z_uL_s7D~$8BmwiInsndNygbPg08e_(Ez&yqWIKU#L(L2{>n5zxIc8RIduV)ej%@Wb zHdaH3kl$N-`UQdf!5PC8`8$9!xW^0pJke%DRF%8#iyb z|N0-gJwk2)aYFxe0MUpQCd)4xs6J=J0%9H0aAzpVwquT3;sq=IIptR}lEm9$xLKK> zwqV~mha78Y(a_1C=PTRt2EdHw{l`($eSD0N&RpzxBgqh;t3Gh(d0HR|lLIhUO}}@V z#DEBy0>Kq?rNl4_)`a5L41KsN{a6j(Pt?;^rLR$c+B)f4a9oJCmaB2DluXoa|xYXpQR$TuIe1 z;Bh4JPG@SI`r4qv0Dt8n6P~;xZURoUN5@oYWCDeR)4t`e?3YN^@u!8*+3b^mCUhqOf>Q4|XfS}KWuTGW=ZjhDNr1C7+Sr`zpK1VYbZ-*F)HwaaJ6 zBm$vl%cP7r*Yg$cA4(4h-H#UM?yN{ef4HmZn>G-NMj55V20};a#N)69Mm5@j&=%aR z%;Pz*@4SZ`W=z$VC=Equs%OPVh*DwEN-B7pGh7p3em(+lYXn5N?75 z;|K@jGr2SxFtjIs-88Wp()#5F-&54n@n-=Hp5yrvLiHq)C zood(MahN;LdYsb)427_Xo~hDrKuo=ysc2Veu~3zQH!2wV(Yb&1kfy1Dp)^_*%2Z>- zQjVL%4MTY|wWW;zz<+@?&_K<4htB6Gf}sOw={OjA{Ql0Y^uW-;I@wbq7}|T_y$K@- zhHA0T#+@q~jp!)-_f?>d07JFd=Ue)IRF3v literal 0 HcmV?d00001 diff --git a/resources/SimpleTest3D.med b/resources/SimpleTest3D.med new file mode 100644 index 0000000000000000000000000000000000000000..62bbc2e5ba5d7f6ca6927fb4cf936f6349f2fc36 GIT binary patch literal 16098 zcmeI3TWnlM9mZ$ZiQ_shxisZcO1fz-b($viEf+h1c;u-` zrS|u@(zblIdiecOi3uaJ(xpS+lpi4mnSN!|2 zU!R%?tF*0tq}}KHQ%m>l3vE#aj;qhw`&~`D_x2=GZ=B=i^&%09KJoI&)~m}zs?#&FZerEa^Mxb(pYYIx-AmoJXY zOyzCdZ#&Box4w-z_ou26DGjm(b;ktr@ zcbu=7@45mT+qn$?;R|0f->54%({uhl^ZPoNKhKRmXo_`VUw!=VFPS&$!fv1FdeywQ z&gJL-+4C>+$-06EUcUI+uXeBhjVoGB&GbOy?dof(jdoqUq30V9v*_96nESRw+As?? z?b6Aa#HP*CiWwG~Gn_urq~i36CKXG$MHKf&&$KOW)lOT(O_`&$XWGDeGw`O}sCjg_ zepuM3a;3ROjgBR&;3hlir!Q^$>T;fM(J^4OT;6w8B-QxI?S^qe2ZV@!|!J z4xLoT;n%2x~mp$=QSw$y~`_Oo@7MB{cY9GsEl;8azC1%`_bj@>7(JbmxpCvJF8td;a zaMJdt802P4<=N>J&P`q$2{jJrUMB7c-^`79HZr_?A6dNNeJbh{ zhVYrc{O#ycGtS;EMoGBzjGMn+9=ZcT4`Qnq0tjy*x z7L*ffzDJ9`>Bhwj{kzB`Pu)4U)R@w>U=w3HpwZ9`XKRk>H7EZ#znmp_`M&xW-0QE@ zef9I7d;OQosghmKDbtnD77J7MsdOr+luv&^L-b+ca$)D(GtV@x(z*1FR+J4P@rM&` zm^#~S-NFgp%rrS(OstMt%?E3r-uj1qJ6=DUuT}%Y9dgQE+HMb@fVnLYSJ(%mY&L6{M46S{$QX?p}_htS?GhiRAaCZW69c4>D6 z=4Rm@;VnXYkr$?Y!dr!0TiT;nnEHhMLiU^e${!FO6dn>XLxz+OZ@}&6Bg(TF^hZIX z3lTFcJ}Vp%jtcD^f0$V3dF98101M>%%HW0PPVphvyn$>Ya5gD20rK@UH44<38s zQH~w);ymr7-SFh&`vN@s1nZo5_@T>wfDU%}!DEjd<=7FAcF->Ls24nW{MgUn$+JJ9 zhabA}_}JkGk3I1y$BuZ66Z@bJ(TRPQ`AEN@k3V_#P4w_XS0`tK4tDs#V~-u>*b$HU z$Nr5T^@1mlAN>YTp8Xy@{LqcZ#|}Su?1@J?cEpSGw3BwjlaJ3sc*d9K6Y=mvm**Hd z*x?6{J$961M?Bg=yU?Rv@Z|Ah9>SC754Y&yhi*JRcKE?#Pdv)8BOc?+JY~OT-y_dH z!g_=!Pd(9tN0)Ix2VMN&u}6n;?1+aB^A~&KvagfJkNpOoJmY{KJi77t=;8;DJvx+Q zM?C5SPdjNBJbCtE_A_|$j5B)h=rWJdK^H%G?9rhdJK~{3yRav2yq);5@4}O3KB5PY zZahA5@Po%59m=sI9`#|LV!w^gKl1T@VVsG_dP5H$UG@`n(8UiPdvqwrj(F&>|6)&E z<{x?d=ofhM>?7#GqZ^NpE`IRXqeD4%#G^j&w3BwhlaJ3sc*d9g4Lx{t*}u_27e9FH z(V-kW;-N#kuqST3o%k^i;mNZvqX&;}JU(&ogU22n%CRFJ_2K=^hrHMMkoP?w@*e2J zjNV6lxJ|qdw~P1T4)H$RDc*;>#QX3j@jmPp@57tL`*4qVAKoI~hkM2QaG!V|-YVXQ zz2be?C*Fts;(a(E-iQ0e`|yBxA086#!$I*r91`!t!{U9&{ecg;SMVYC3_cuId>>}T z`*1|O4@brOFel!JdGS6R6Ys-u@jfhw_u+(iA5Mz*VNtvfOX7W47VpDp@jg5z-iH0-?sQR}ma$no37^weS6{l4HR>i97->RtUufl2%toFca53KgU z|5*>@$8#fwuOo(Sf3!3BMD2T?L3KLuUlVQWqMA{zko?z*gwf1LlS=fpQwsknG8a_C z|4c|(Chgc7bG$T@WWukaRx8Ob*VGG#MwOt6=%sQojN$GwT=dLaO!c)bteDb?P|3aD zxH_G_t8f2c@4#RtfA?oI#nX3ZdJkrL4-5_T4fXV9`g;2MGyMYt2YL>LbqSlk*mtyQ SLs&ZL|2CD4x|-gtJ@8+KiyiO) literal 0 HcmV?d00001 diff --git a/resources/Test2DMultiGeoType.med b/resources/Test2DMultiGeoType.med new file mode 100644 index 0000000000000000000000000000000000000000..dc6cf553338c9ba054a633a1674dfa0371df2d0a GIT binary patch literal 8678 zcmeGhTWl0n^v-O%tlO2g*eZg+7DG})FuU7DyG7FOc4xa=c4n5D-HKJyq7aCrvDgwT zKN=DhZ4B|p@F5|_X!vL~=nt3_j2esq8uUjcX$c<`Q6w6EP%(J#%sI0=JF^elVyx~> z+B19ax#xZEIWzaQcrk=eE2`2^hb0F%ZJ2|pQkkmdg93G|kY&aLQSw}3aPA}JI zh{ge)4RG`5jX`^n#*2y6xP(+$#r3Qq#6cH4Y*7q%lR9b>-7Fo1r#$JjHq3|#$$|)4 z5EG&zBnu+GxanNjUXS9Ytz~Aa8rVLxb0rgy4M7KU{{L3f)ccx9O}Ud&Fg%Y;kTQcaDx0EH07N2`A-lyR5N)vro>ZPSn{MUs}$zkpJ1?E7_9ja z4V&Fs^oedq3ec4DKN>=S&RwPVOhuIa{s{ zbiP40=CHkT@cMUTI*0B3-JUDt?wl=WZmzvS`g0~mFP{HxX5R&>NM)2~0sG@=A6G~7 z;u_R5EM9soVk;vJI(1wz9n#X4wB?Y-)XGCll!ut=DU)KVr%Z}cvS$ z9SwxDGkCR&a6Hdz7IIPP99$d7_9;-X*VF8rh}AiGzM2q=I%i&vm%ZARQmq=6WrPk7;c~z4SX;E;p`!IuUD)`?TC{GR-~9Y5Bp?*f;Yg zB_uhzp;0Gf&ybnnQSHr~kYhSx_WPq)dk;)uf1~}Z7N7ZH{v)mzdaQn6X)muSEhL+l z0_@C8h(*0KuMrnq>h7JN!=X!%EjfQ0Y*V&!d5DEik#{bR94qBhG%do?r^qMZQ}2TI zsrc-VlXFVJYjDokhcrt;H~rYghBXC0gB9adOT&9Gvp-()eSUK$xE451yLJzkaxWD_ z8wg9g_dK}wCD>`NpD70ag()TzWe2S@xu(VHm zp-1p8XrI=PpA~15ve_%8-S>e31b}k|!yla*osCGe1arg_3yX;)Z6tdIMXtj8hmCWT z>2l!BU+qO2<5yGK_?5j5WM!` z=sk-=`^58Y|HPNEcr-%rN=~Cb`qLk)jk``kOu3e0L61!E;6rL8O4b*!pbKRD+S){qpT4DOOFYCM{NySK#9u7owYGg4yKJA1U9 z4*<`ty8`P&{$R+P-m~2+Zhg)h@O%BfHeYL7u*Dnj1zNlh1w#H%YxX+2*u8||B56zE N8w4~~1^y2$@D~~_qM-l) literal 0 HcmV?d00001 diff --git a/src/MEDLoader/MEDFileField1TS.cxx b/src/MEDLoader/MEDFileField1TS.cxx index bd3db0525..671cfede1 100644 --- a/src/MEDLoader/MEDFileField1TS.cxx +++ b/src/MEDLoader/MEDFileField1TS.cxx @@ -772,6 +772,27 @@ void MEDFileAnyTypeField1TSWithoutSDA::loadOnlyStructureOfDataRecursively(med_id _field_per_mesh[0]->loadOnlyStructureOfDataRecursively(fid,_nb_of_tuples_to_be_allocated,nasc); } +void MEDFileAnyTypeField1TSWithoutSDA::loadOnlyStructureOfDataRecursively(med_idt fid, const MEDFileFieldNameScope& nasc, const PartDefinition *pd, const MEDFileEntities *entities, const MEDFileCapability *capability) +{ + med_int numdt,numit; + med_float dt; + med_int meshnumdt(-1),meshnumit(-1); + MEDFILESAFECALLERRD0(MEDfieldComputingStepInfo,(fid,nasc.getName().c_str(),_csit,&numdt,&numit,&_dt)); + if(!capability || !capability->isFastReader()) + { + med_bool localMesh; + med_int nmesh; + INTERP_KERNEL::AutoPtr meshName(MEDLoaderBase::buildEmptyString(MED_NAME_SIZE)); + MEDFILESAFECALLERRD0(MEDfield23ComputingStepMeshInfo,(fid,nasc.getName().c_str(),_csit,&numdt,&numit,&dt,&nmesh,meshName,&localMesh,&meshnumdt,&meshnumit)); // to check with Adrien for legacy MED files + } + if(_iteration!=numdt || _order!=numit) + throw INTERP_KERNEL::Exception("MEDFileAnyTypeField1TSWithoutSDA::loadBigArraysRecursively : unexpected exception internal error !"); + _field_per_mesh.resize(1); + _field_per_mesh[0]=MEDFileFieldPerMesh::NewOnRead(fid,this,0,FromMedInt(meshnumdt),FromMedInt(meshnumit),nasc,pd,entities); + _nb_of_tuples_to_be_allocated=0; + _field_per_mesh[0]->loadOnlyStructureOfDataRecursively(fid,_nb_of_tuples_to_be_allocated,nasc); +} + void MEDFileAnyTypeField1TSWithoutSDA::loadBigArraysRecursively(med_idt fid, const MEDFileFieldNameScope& nasc) { allocIfNecessaryTheArrayToReceiveDataFromFile(); @@ -793,6 +814,13 @@ void MEDFileAnyTypeField1TSWithoutSDA::loadStructureAndBigArraysRecursively(med_ loadBigArraysRecursively(fid,nasc); } +void MEDFileAnyTypeField1TSWithoutSDA::loadStructureAndBigArraysRecursively(med_idt fid, const MEDFileFieldNameScope& nasc, const PartDefinition *pd, const MEDFileEntities *entities) +{ + MEDFileCapability cap(fid); + loadOnlyStructureOfDataRecursively(fid,nasc,pd,entities,&cap); + loadBigArraysRecursively(fid,nasc); +} + void MEDFileAnyTypeField1TSWithoutSDA::unloadArrays() { DataArray *thisArr(getUndergroundDataArray()); @@ -1774,58 +1802,101 @@ MEDFileAnyTypeField1TS::MEDFileAnyTypeField1TS() { } -MEDFileAnyTypeField1TSWithoutSDA *MEDFileAnyTypeField1TS::BuildContentFrom(med_idt fid, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities) +MEDFileAnyTypeField1TSWithoutSDA *MEDFileAnyTypeField1TS::AllocateContentFrom(med_idt fid, const std::string& fieldName, int iteration, int order) { + MCAuto ret; med_field_type typcha; - // std::vector infos; - std::string dtunit,fieldName,meshName; - LocateField2(fid,0,true,fieldName,typcha,infos,dtunit,meshName); - MCAuto ret; + std::string dtunit,meshName; + int iii(-1); + int nbOfStep2(-1); + std::string fName(fieldName); + if(fName.empty()) + LocateField2(fid,0,true,fName,typcha,infos,dtunit,meshName); + nbOfStep2=LocateField(fid,fName,iii,typcha,infos,dtunit,meshName); + if(nbOfStep2<1) + { + std::ostringstream oss; oss << "MEDFileField1TS(fid,fName) : file \'" << FileNameFromFID(fid) << "\' contains field with name \'" << fName << "\' but there is no time steps on it !"; + throw INTERP_KERNEL::Exception(oss.str()); + } + switch(typcha) { case MED_FLOAT64: { - ret=MEDFileField1TSWithoutSDA::New(fieldName,meshName,-1,-1/*iteration*/,-1/*order*/,std::vector()); + ret=MEDFileField1TSWithoutSDA::New(fName,meshName,-1,iteration,order,std::vector()); break; } case MED_INT32: { - ret=MEDFileInt32Field1TSWithoutSDA::New(fieldName,meshName,-1,-1/*iteration*/,-1/*order*/,std::vector()); + ret=MEDFileInt32Field1TSWithoutSDA::New(fName,meshName,-1,iteration,order,std::vector()); break; } case MED_INT64: { - ret=MEDFileInt64Field1TSWithoutSDA::New(fieldName,meshName,-1,-1/*iteration*/,-1/*order*/,std::vector()); + ret=MEDFileInt64Field1TSWithoutSDA::New(fName,meshName,-1,iteration,order,std::vector()); break; } case MED_FLOAT32: { - ret=MEDFileFloatField1TSWithoutSDA::New(fieldName,meshName,-1,-1/*iteration*/,-1/*order*/,std::vector()); + ret=MEDFileFloatField1TSWithoutSDA::New(fName,meshName,-1,iteration,order,std::vector()); break; } case MED_INT: { if(sizeof(med_int)==sizeof(int)) { - ret=MEDFileInt32Field1TSWithoutSDA::New(fieldName,meshName,-1,-1/*iteration*/,-1/*order*/,std::vector()); + ret=MEDFileInt32Field1TSWithoutSDA::New(fName,meshName,-1,iteration,order,std::vector()); break; } } default: { - std::ostringstream oss; oss << "MEDFileAnyTypeField1TS::BuildContentFrom(fid) : file \'" << FileNameFromFID(fid) << "\' contains field with name \'" << fieldName << "\' but the type of the first field is not in [MED_FLOAT64, MED_FLOAT32, MED_INT32, MED_INT64] !"; + std::ostringstream oss; oss << "MEDFileAnyTypeField1TS::AllocateContentFrom(fid,fName,iteration,order) : file \'" << FileNameFromFID(fid) << "\' contains field with name \'" << fName << "\' but the type of field is not in [MED_FLOAT64, MED_INT32, MED_FLOAT32, MED_INT64] !"; throw INTERP_KERNEL::Exception(oss.str()); } } ret->setDtUnit(dtunit.c_str()); ret->getOrCreateAndGetArray()->setInfoAndChangeNbOfCompo(infos); - // - med_int numdt,numit; - med_float dt; - MEDFILESAFECALLERRD0(MEDfieldComputingStepInfo,(fid,fieldName.c_str(),1,&numdt,&numit,&dt)); - ret->setTime(FromMedInt(numdt),FromMedInt(numit),dt); - ret->_csit=1; + + // searching for timestep given in parameter + bool found=false; + std::vector< std::pair > dtits(nbOfStep2); + for(int i=0;i_csit=i+1; + ret->setTime(FromMedInt(numdt),FromMedInt(numit),dt); + } + else if(numdt==iteration && numit==order) // or we found the correct timestep + { + found=true; + ret->_csit=i+1; + } + else + dtits[i]=std::pair(numdt,numit); + } + if(!found) + { + std::ostringstream oss; oss << "No such iteration (" << iteration << "," << order << ") in existing field '" << fName << "' in file '" << FileNameFromFID(fid) << "' ! Available iterations are : "; + for(std::vector< std::pair >::const_iterator iter=dtits.begin();iter!=dtits.end();iter++) + oss << "(" << (*iter).first << "," << (*iter).second << "), "; + throw INTERP_KERNEL::Exception(oss.str()); + } + + return ret.retn(); + +} + +MEDFileAnyTypeField1TSWithoutSDA *MEDFileAnyTypeField1TS::BuildContentFrom(med_idt fid, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities) +{ + std::string useless; + MCAuto ret(AllocateContentFrom(fid,useless)); if(loadAll) ret->loadStructureAndBigArraysRecursively(fid,*((const MEDFileAnyTypeField1TSWithoutSDA*)ret),ms,entities); else @@ -1833,6 +1904,34 @@ MEDFileAnyTypeField1TSWithoutSDA *MEDFileAnyTypeField1TS::BuildContentFrom(med_i return ret.retn(); } +MEDFileAnyTypeField1TSWithoutSDA *MEDFileAnyTypeField1TS::BuildContentFrom(med_idt fid, const std::string& fieldName, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities) +{ + MCAuto ret(AllocateContentFrom(fid,fieldName)); + if(loadAll) + ret->loadStructureAndBigArraysRecursively(fid,*((const MEDFileAnyTypeField1TSWithoutSDA*)ret),ms,entities); + else + ret->loadOnlyStructureOfDataRecursively(fid,*((const MEDFileAnyTypeField1TSWithoutSDA*)ret),ms,entities); + return ret.retn(); +} + +MEDFileAnyTypeField1TSWithoutSDA *MEDFileAnyTypeField1TS::BuildContentFrom(med_idt fid, const std::string& fieldName, int iteration, int order, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities) +{ + MCAuto ret(AllocateContentFrom(fid,fieldName,iteration,order)); + if(loadAll) + ret->loadStructureAndBigArraysRecursively(fid,*((const MEDFileAnyTypeField1TSWithoutSDA*)ret),ms,entities); + else + ret->loadOnlyStructureOfDataRecursively(fid,*((const MEDFileAnyTypeField1TSWithoutSDA*)ret),ms,entities); + return ret.retn(); +} + +MEDFileAnyTypeField1TSWithoutSDA *MEDFileAnyTypeField1TS::BuildContentFrom(med_idt fid, const std::string& fieldName, int iteration, int order, const PartDefinition *pd, const MEDFileEntities *entities) +{ + MCAuto ret(AllocateContentFrom(fid,fieldName,iteration,order)); + ret->loadStructureAndBigArraysRecursively(fid,*((const MEDFileAnyTypeField1TSWithoutSDA*)ret),pd,entities); + return ret.retn(); +} + + MEDFileAnyTypeField1TS::MEDFileAnyTypeField1TS(med_idt fid, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities) try:MEDFileFieldGlobsReal(fid) { @@ -1844,79 +1943,21 @@ catch(INTERP_KERNEL::Exception& e) throw e; } -MEDFileAnyTypeField1TSWithoutSDA *MEDFileAnyTypeField1TS::BuildContentFrom(med_idt fid, const std::string& fieldName, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities) +MEDFileAnyTypeField1TS::MEDFileAnyTypeField1TS(med_idt fid, const std::string& fieldName, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities) +try:MEDFileFieldGlobsReal(fid) { - med_field_type typcha; - std::vector infos; - std::string dtunit,meshName; - int nbSteps(0); - { - int iii=-1; - nbSteps=LocateField(fid,fieldName,iii,typcha,infos,dtunit,meshName); - } - MCAuto ret; - switch(typcha) - { - case MED_FLOAT64: - { - ret=MEDFileField1TSWithoutSDA::New(fieldName,meshName,-1,-1/*iteration*/,-1/*order*/,std::vector()); - break; - } - case MED_INT32: - { - ret=MEDFileInt32Field1TSWithoutSDA::New(fieldName,meshName,-1,-1/*iteration*/,-1/*order*/,std::vector()); - break; - } - case MED_INT64: - { - ret=MEDFileInt64Field1TSWithoutSDA::New(fieldName,meshName,-1,-1/*iteration*/,-1/*order*/,std::vector()); - break; - } - case MED_FLOAT32: - { - ret=MEDFileFloatField1TSWithoutSDA::New(fieldName,meshName,-1,-1/*iteration*/,-1/*order*/,std::vector()); - break; - } - case MED_INT: - { - if(sizeof(med_int)==sizeof(int)) - { - ret=MEDFileInt32Field1TSWithoutSDA::New(fieldName,meshName,-1,-1/*iteration*/,-1/*order*/,std::vector()); - break; - } - } - default: - { - std::ostringstream oss; oss << "MEDFileAnyTypeField1TS::BuildContentFrom(fid,fieldName) : file \'" << FileNameFromFID(fid) << "\' contains field with name \'" << fieldName << "\' but the type of field is not in [MED_FLOAT64, MED_INT32, MED_FLOAT32, MED_INT64] !"; - throw INTERP_KERNEL::Exception(oss.str()); - } - } - ret->setMeshName(meshName); - ret->setDtUnit(dtunit.c_str()); - ret->getOrCreateAndGetArray()->setInfoAndChangeNbOfCompo(infos); - // - if(nbSteps<1) - { - std::ostringstream oss; oss << "MEDFileField1TS(fid,fieldName) : file \'" << FileNameFromFID(fid) << "\' contains field with name \'" << fieldName << "\' but there is no time steps on it !"; - throw INTERP_KERNEL::Exception(oss.str()); - } - // - med_int numdt,numit; - med_float dt; - MEDFILESAFECALLERRD0(MEDfieldComputingStepInfo,(fid,fieldName.c_str(),1,&numdt,&numit,&dt)); - ret->setTime(FromMedInt(numdt),FromMedInt(numit),dt); - ret->_csit=1; - if(loadAll) - ret->loadStructureAndBigArraysRecursively(fid,*((const MEDFileAnyTypeField1TSWithoutSDA*)ret),ms,entities); - else - ret->loadOnlyStructureOfDataRecursively(fid,*((const MEDFileAnyTypeField1TSWithoutSDA*)ret),ms,entities); - return ret.retn(); + _content=BuildContentFrom(fid,fieldName,loadAll,ms,entities); + loadGlobals(fid); +} +catch(INTERP_KERNEL::Exception& e) +{ + throw e; } -MEDFileAnyTypeField1TS::MEDFileAnyTypeField1TS(med_idt fid, const std::string& fieldName, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities) +MEDFileAnyTypeField1TS::MEDFileAnyTypeField1TS(med_idt fid, const std::string& fieldName, int iteration, int order, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities) try:MEDFileFieldGlobsReal(fid) { - _content=BuildContentFrom(fid,fieldName,loadAll,ms,entities); + _content=BuildContentFrom(fid,fieldName,iteration,order,loadAll,ms,entities); loadGlobals(fid); } catch(INTERP_KERNEL::Exception& e) @@ -1976,6 +2017,7 @@ MEDFileAnyTypeField1TS *MEDFileAnyTypeField1TS::New(med_idt fid, bool loadAll) return ret.retn(); } + MEDFileAnyTypeField1TS *MEDFileAnyTypeField1TS::New(const std::string& fileName, const std::string& fieldName, bool loadAll) { MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName)); @@ -1998,7 +2040,7 @@ MEDFileAnyTypeField1TS *MEDFileAnyTypeField1TS::New(const std::string& fileName, MEDFileAnyTypeField1TS *MEDFileAnyTypeField1TS::New(med_idt fid, const std::string& fieldName, int iteration, int order, bool loadAll) { - MCAuto c(BuildContentFrom(fid,fieldName,iteration,order,loadAll,0,0)); + MCAuto c(BuildContentFrom(fid,fieldName,iteration,order,loadAll,(const MEDFileMeshes *)0,0)); MCAuto ret(BuildNewInstanceFromContent(c,fid)); ret->loadGlobals(fid); return ret.retn(); @@ -2012,98 +2054,24 @@ MEDFileAnyTypeField1TS *MEDFileAnyTypeField1TS::NewAdv(const std::string& fileNa MEDFileAnyTypeField1TS *MEDFileAnyTypeField1TS::NewAdv(med_idt fid, const std::string& fieldName, int iteration, int order, bool loadAll, const MEDFileEntities *entities) { - MCAuto c(BuildContentFrom(fid,fieldName,iteration,order,loadAll,0,entities)); + MCAuto c(BuildContentFrom(fid,fieldName,iteration,order,loadAll,(const MEDFileMeshes *)0,entities)); MCAuto ret(BuildNewInstanceFromContent(c,fid)); ret->loadGlobals(fid); return ret.retn(); } -MEDFileAnyTypeField1TSWithoutSDA *MEDFileAnyTypeField1TS::BuildContentFrom(med_idt fid, const std::string& fieldName, int iteration, int order, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities) + +MEDFileAnyTypeField1TS *MEDFileAnyTypeField1TS::NewAdv(med_idt fid, const std::string& fieldName, int iteration, int order, const MEDFileEntities *entities, const std::vector& distrib) { - med_field_type typcha; - std::vector infos; - std::string dtunit,meshName; - int iii(-1); - int nbOfStep2(LocateField(fid,fieldName,iii,typcha,infos,dtunit,meshName)); - MCAuto ret; - switch(typcha) - { - case MED_FLOAT64: - { - ret=MEDFileField1TSWithoutSDA::New(fieldName,meshName,-1,iteration,order,std::vector()); - break; - } - case MED_INT32: - { - ret=MEDFileInt32Field1TSWithoutSDA::New(fieldName,meshName,-1,iteration,order,std::vector()); - break; - } - case MED_INT64: - { - ret=MEDFileInt64Field1TSWithoutSDA::New(fieldName,meshName,-1,iteration,order,std::vector()); - break; - } - case MED_FLOAT32: - { - ret=MEDFileFloatField1TSWithoutSDA::New(fieldName,meshName,-1,iteration,order,std::vector()); - break; - } - case MED_INT: - { - if(sizeof(med_int)==sizeof(int)) - { - ret=MEDFileInt32Field1TSWithoutSDA::New(fieldName,meshName,-1,iteration,order,std::vector()); - break; - } - } - default: - { - std::ostringstream oss; oss << "MEDFileAnyTypeField1TS::BuildContentFrom(fid,fieldName,iteration,order) : file \'" << FileNameFromFID(fid) << "\' contains field with name \'" << fieldName << "\' but the type of field is not in [MED_FLOAT64, MED_INT32, MED_FLOAT32, MED_INT64] !"; - throw INTERP_KERNEL::Exception(oss.str()); - } - } - ret->setDtUnit(dtunit.c_str()); - ret->getOrCreateAndGetArray()->setInfoAndChangeNbOfCompo(infos); - // - bool found=false; - std::vector< std::pair > dtits(nbOfStep2); - for(int i=0;i_csit=i+1; - } - else - dtits[i]=std::pair(numdt,numit); - } - if(!found) - { - std::ostringstream oss; oss << "No such iteration (" << iteration << "," << order << ") in existing field '" << fieldName << "' in file '" << FileNameFromFID(fid) << "' ! Available iterations are : "; - for(std::vector< std::pair >::const_iterator iter=dtits.begin();iter!=dtits.end();iter++) - oss << "(" << (*iter).first << "," << (*iter).second << "), "; - throw INTERP_KERNEL::Exception(oss.str()); - } - if(loadAll) - ret->loadStructureAndBigArraysRecursively(fid,*((const MEDFileAnyTypeField1TSWithoutSDA*)ret),ms,entities); - else - ret->loadOnlyStructureOfDataRecursively(fid,*((const MEDFileAnyTypeField1TSWithoutSDA*)ret),ms,entities); + MCAuto listOfIds=DataArrayIdType::New(); + listOfIds->useArray(distrib.data(),false,DeallocType::C_DEALLOC,distrib.size(),1); + MCAuto pd=PartDefinition::New(listOfIds); + MCAuto c(BuildContentFrom(fid,fieldName,iteration,order,pd,entities)); + MCAuto ret(BuildNewInstanceFromContent(c,fid)); + ret->loadGlobals(fid); return ret.retn(); } -MEDFileAnyTypeField1TS::MEDFileAnyTypeField1TS(med_idt fid, const std::string& fieldName, int iteration, int order, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities) -try:MEDFileFieldGlobsReal(fid) -{ - _content=BuildContentFrom(fid,fieldName,iteration,order,loadAll,ms,entities); - loadGlobals(fid); -} -catch(INTERP_KERNEL::Exception& e) -{ - throw e; -} /*! * This constructor is a shallow copy constructor. If \a shallowCopyOfContent is true the content of \a other is shallow copied. diff --git a/src/MEDLoader/MEDFileField1TS.hxx b/src/MEDLoader/MEDFileField1TS.hxx index 55864e3f7..dffcfa3e8 100644 --- a/src/MEDLoader/MEDFileField1TS.hxx +++ b/src/MEDLoader/MEDFileField1TS.hxx @@ -117,9 +117,11 @@ namespace MEDCoupling MEDLOADER_EXPORT void allocNotFromFile(mcIdType newNbOfTuples); MEDLOADER_EXPORT bool allocIfNecessaryTheArrayToReceiveDataFromFile(); MEDLOADER_EXPORT void loadOnlyStructureOfDataRecursively(med_idt fid, const MEDFileFieldNameScope& nasc, const MEDFileMeshes *ms, const MEDFileEntities *entities, const MEDFileCapability *capability = nullptr); + MEDLOADER_EXPORT void loadOnlyStructureOfDataRecursively(med_idt fid, const MEDFileFieldNameScope& nasc, const PartDefinition *pd, const MEDFileEntities *entities, const MEDFileCapability *capability = nullptr); MEDLOADER_EXPORT void loadBigArraysRecursively(med_idt fid, const MEDFileFieldNameScope& nasc); MEDLOADER_EXPORT void loadBigArraysRecursivelyIfNecessary(med_idt fid, const MEDFileFieldNameScope& nasc); MEDLOADER_EXPORT void loadStructureAndBigArraysRecursively(med_idt fid, const MEDFileFieldNameScope& nasc, const MEDFileMeshes *ms, const MEDFileEntities *entities); + MEDLOADER_EXPORT void loadStructureAndBigArraysRecursively(med_idt fid, const MEDFileFieldNameScope& nasc, const PartDefinition *pd, const MEDFileEntities *entities); MEDLOADER_EXPORT void unloadArrays(); MEDLOADER_EXPORT void writeLL(med_idt fid, const MEDFileWritable& opts, const MEDFileFieldNameScope& nasc) const; MEDLOADER_EXPORT static std::string FieldNameToMEDFileConvention(const std::string& nonCorrectFieldName); @@ -278,6 +280,8 @@ namespace MEDCoupling MEDLOADER_EXPORT static MEDFileAnyTypeField1TSWithoutSDA *BuildContentFrom(med_idt fid, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities); MEDLOADER_EXPORT static MEDFileAnyTypeField1TSWithoutSDA *BuildContentFrom(med_idt fid, const std::string& fieldName, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities); MEDLOADER_EXPORT static MEDFileAnyTypeField1TSWithoutSDA *BuildContentFrom(med_idt fid, const std::string& fieldName, int iteration, int order, bool loadAll, const MEDFileMeshes *ms, const MEDFileEntities *entities); + MEDLOADER_EXPORT static MEDFileAnyTypeField1TSWithoutSDA *BuildContentFrom(med_idt fid, const std::string& fieldName, int iteration, int order, const PartDefinition *pd, const MEDFileEntities *entities); + MEDLOADER_EXPORT static MEDFileAnyTypeField1TSWithoutSDA *AllocateContentFrom(med_idt fid, const std::string& fieldName, int iteration=-1, int order=-1); MEDLOADER_EXPORT void writeLL(med_idt fid) const; // direct forwarding to MEDFileAnyTypeField1TSWithoutSDA instance _content public: @@ -289,6 +293,8 @@ namespace MEDCoupling MEDLOADER_EXPORT static MEDFileAnyTypeField1TS *New(med_idt fid, const std::string& fieldName, int iteration, int order, bool loadAll=true); MEDLOADER_EXPORT static MEDFileAnyTypeField1TS *NewAdv(const std::string& fileName, const std::string& fieldName, int iteration, int order, bool loadAll, const MEDFileEntities *entities); MEDLOADER_EXPORT static MEDFileAnyTypeField1TS *NewAdv(med_idt fid, const std::string& fieldName, int iteration, int order, bool loadAll, const MEDFileEntities *entities); + MEDLOADER_EXPORT static MEDFileAnyTypeField1TS *NewAdv(med_idt fid, const std::string& fieldName, int iteration, int order, const MEDFileEntities *entities, const std::vector& distrib); + MEDLOADER_EXPORT int getDimension() const; MEDLOADER_EXPORT int getIteration() const; MEDLOADER_EXPORT int getOrder() const; @@ -374,6 +380,7 @@ namespace MEDCoupling MEDLOADER_EXPORT static typename MLFieldTraits::F1TSType *New(const std::string& fileName, const std::string& fieldName, int iteration, int order, bool loadAll=true); MEDLOADER_EXPORT static typename MLFieldTraits::F1TSType *New(med_idt fid, const std::string& fieldName, int iteration, int order, bool loadAll=true); MEDLOADER_EXPORT static typename MLFieldTraits::F1TSType *New(const typename MLFieldTraits::F1TSWSDAType& other, bool shallowCopyOfContent); + public: MEDLOADER_EXPORT static typename Traits::ArrayType *ReturnSafelyTypedDataArray(MCAuto& arr); MEDLOADER_EXPORT typename Traits::ArrayType *getFieldWithProfile(TypeOfField type, int meshDimRelToMax, const MEDFileMesh *mesh, DataArrayIdType *&pfl) const; diff --git a/src/MEDLoader/MEDFileFieldInternal.cxx b/src/MEDLoader/MEDFileFieldInternal.cxx index 640b42393..1906229d4 100644 --- a/src/MEDLoader/MEDFileFieldInternal.cxx +++ b/src/MEDLoader/MEDFileFieldInternal.cxx @@ -30,6 +30,8 @@ #include "MEDCouplingFieldTemplate.hxx" #include "MEDCouplingFieldDouble.hxx" +#include "MEDFilterEntity.hxx" + #include "CellModel.hxx" // From MEDLOader.cxx TU @@ -591,47 +593,15 @@ void MEDFileFieldPerMeshPerTypePerDisc::goReadZeValuesInFile(med_idt fid, const INTERP_KERNEL::AutoPtr pflname(MEDLoaderBase::buildEmptyString(MED_NAME_SIZE)),locname(MEDLoaderBase::buildEmptyString(MED_NAME_SIZE)); med_int profilesize,nbi; med_int overallNval(MEDfieldnValueWithProfile(fid,fieldName.c_str(),iteration,order,menti,mgeoti,FromIdType(_profile_it+1),MED_COMPACT_PFLMODE,pflname,&profilesize,locname,&nbi)); - const SlicePartDefinition *spd(dynamic_cast(pd)); - if(spd) - { - mcIdType start,stop,step; - spd->getSlice(start,stop,step); - mcIdType nbOfEltsToLoad(DataArray::GetNumberOfItemGivenBES(start,stop,step,"MEDFileFieldPerMeshPerTypePerDisc::goReadZeValuesInFile")); - med_filter filter=MED_FILTER_INIT; - MEDFILESAFECALLERRD0(MEDfilterBlockOfEntityCr,(fid,/*nentity*/overallNval,/*nvaluesperentity*/nbi,/*nconstituentpervalue*/nbOfCompo, - MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, - /*start*/ToMedInt(start+1),/*stride*/ToMedInt(step),/*count*/1,/*blocksize*/ToMedInt(nbOfEltsToLoad), - /*lastblocksize=useless because count=1*/0,&filter)); - MEDFILESAFECALLERRD0(MEDfieldValueAdvancedRd,(fid,fieldName.c_str(),iteration,order,menti,mgeoti,&filter,startFeedingPtr)); - MEDfilterClose(&filter); - return ; - } - const DataArrayPartDefinition *dpd(dynamic_cast(pd)); - if(dpd) - { - dpd->checkConsistencyLight(); - MCAuto myIds(dpd->toDAI()); - mcIdType a(myIds->getMinValueInArray()),b(myIds->getMaxValueInArray()); - myIds=myIds->deepCopy();// WARNING deep copy here because _pd is modified by applyLin !!! - myIds->applyLin(1,-a); - mcIdType nbOfEltsToLoad(b-a+1); - med_filter filter=MED_FILTER_INIT; - {//TODO : manage int32 ! - MCAuto tmp(DataArrayDouble::New()); - tmp->alloc(nbOfEltsToLoad,nbOfCompo); - MEDFILESAFECALLERRD0(MEDfilterBlockOfEntityCr,(fid,/*nentity*/overallNval,/*nvaluesperentity*/nbi,/*nconstituentpervalue*/nbOfCompo, - MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, - /*start*/ToMedInt(a+1),/*stride*/1,/*count*/1,/*blocksize*/ToMedInt(nbOfEltsToLoad), - /*lastblocksize=useless because count=1*/0,&filter)); - MEDFILESAFECALLERRD0(MEDfieldValueAdvancedRd,(fid,fieldName.c_str(),iteration,order,menti,mgeoti,&filter,reinterpret_cast(tmp->getPointer()))); - MCAuto feeder(DataArrayDouble::New()); - feeder->useExternalArrayWithRWAccess(reinterpret_cast(startFeedingPtr),_nval,nbOfCompo); - feeder->setContigPartOfSelectedValues(0,tmp,myIds); - } - MEDfilterClose(&filter); - } - else - throw INTERP_KERNEL::Exception("Not implemented yet for not slices!"); + + {//TODO : manage int32 ! + pd->checkConsistencyLight(); + MEDFilterEntity filter; + filter.fill(fid,/*nentity*/overallNval,/*nvaluesperentity*/nbi,/*nconstituentpervalue*/nbOfCompo, + MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, + pd); + MEDFILESAFECALLERRD0(MEDfieldValueAdvancedRd,(fid,fieldName.c_str(),iteration,order,menti,mgeoti,filter.getPtr(),startFeedingPtr)); + } } } @@ -748,6 +718,7 @@ void MEDFileFieldPerMeshPerTypePerDisc::loadBigArray(med_idt fid, const MEDFileF throw INTERP_KERNEL::Exception("Error on array reading ! Unrecognized type of field ! Should be in FLOAT64 FLOAT32 INT32 or INT64 !"); } + /*! * Set a \c this->_start **and** \c this->_end keeping the same delta between the two. */ @@ -1990,6 +1961,11 @@ MEDFileFieldPerMesh *MEDFileFieldPerMesh::NewOnRead(med_idt fid, MEDFileAnyTypeF return new MEDFileFieldPerMesh(fid,fath,meshCsit,meshIteration,meshOrder,nasc,mm,entities); } +MEDFileFieldPerMesh *MEDFileFieldPerMesh::NewOnRead(med_idt fid, MEDFileAnyTypeField1TSWithoutSDA *fath, int meshCsit, int meshIteration, int meshOrder, const MEDFileFieldNameScope& nasc, const PartDefinition *pd, const MEDFileEntities *entities) +{ + return new MEDFileFieldPerMesh(fid,fath,meshCsit,meshIteration,meshOrder,nasc,pd,entities); +} + MEDFileFieldPerMesh *MEDFileFieldPerMesh::New(MEDFileAnyTypeField1TSWithoutSDA *fath, const MEDCouplingMesh *mesh) { return new MEDFileFieldPerMesh(fath,mesh); @@ -3050,7 +3026,7 @@ DataArray *MEDFileFieldPerMesh::finishField4(const std::vector locName(MEDLoaderBase::buildEmptyString(MED_NAME_SIZE)); const MEDFileUMesh *mmu(dynamic_cast(mm)); INTERP_KERNEL::AutoCppPtr iter0(MFFPMIter::NewCell(entities)); + + // for each geometric type inside my mesh, check if there is a field profile ie if the field is defined on this type of cells (whether the discretization is on cells or on gauss_ne) + // and if this is the case, retrieve the part to be read and build a new MedFileField from it for(iter0->begin();!iter0->finished();iter0->next()) { med_int nbProfile (MEDfield23nProfile(fid,nasc.getName().c_str(),getIteration(),getOrder(),MED_CELL ,typmai[iter0->current()],meshCsit+1,meshName,pflName,locName)); @@ -3170,8 +3149,13 @@ MEDFileFieldPerMesh::MEDFileFieldPerMesh(med_idt fid, MEDFileAnyTypeField1TSWith setMeshName(name1); } } + + + // entities are pairs of a field discretization and geometric type + // if no entities have been passed, then it means we can consider nodes by default if(MFFPMIter::IsPresenceOfNode(entities)) { + // if there is a profile on nodes for the current field, retrieve the part to be read and build a new MedFileField from it med_int nbProfile(MEDfield23nProfile(fid,nasc.getName().c_str(),getIteration(),getOrder(),MED_NODE,MED_NONE,meshCsit+1,meshName,pflName,locName)); if(nbProfile>0) { @@ -3215,6 +3199,41 @@ MEDFileFieldPerMesh::MEDFileFieldPerMesh(med_idt fid, MEDFileAnyTypeField1TSWith } } +MEDFileFieldPerMesh::MEDFileFieldPerMesh(med_idt fid, MEDFileAnyTypeField1TSWithoutSDA *fath, int meshCsit, int meshIteration, int meshOrder, const MEDFileFieldNameScope& nasc, const PartDefinition *pd, const MEDFileEntities *entities):_mesh_iteration(meshIteration),_mesh_order(meshOrder), + _father(fath) +{ + INTERP_KERNEL::AutoPtr meshName(MEDLoaderBase::buildEmptyString(MED_NAME_SIZE)); + INTERP_KERNEL::AutoPtr pflName(MEDLoaderBase::buildEmptyString(MED_NAME_SIZE)); + INTERP_KERNEL::AutoPtr locName(MEDLoaderBase::buildEmptyString(MED_NAME_SIZE)); + INTERP_KERNEL::AutoCppPtr iter0(MFFPMIter::NewCell(entities)); + for(iter0->begin();!iter0->finished();iter0->next()) + { + med_int nbProfile (MEDfield23nProfile(fid,nasc.getName().c_str(),getIteration(),getOrder(),MED_CELL ,typmai[iter0->current()],meshCsit+1,meshName,pflName,locName)); + std::string name0(MEDLoaderBase::buildStringFromFortran(meshName,MED_NAME_SIZE+1)); + med_int nbProfile2(MEDfield23nProfile(fid,nasc.getName().c_str(),getIteration(),getOrder(),MED_NODE_ELEMENT,typmai[iter0->current()],meshCsit+1,meshName,pflName,locName)); + std::string name1(MEDLoaderBase::buildStringFromFortran(meshName,MED_NAME_SIZE+1)); + if(nbProfile>0 || nbProfile2>0) + { + _field_pm_pt.push_back(MEDFileFieldPerMeshPerType::NewOnRead(fid,this,ON_CELLS,typmai2[iter0->current()],nasc,pd)); + if(nbProfile>0) + setMeshName(name0); + else + setMeshName(name1); + } + } + + if(MFFPMIter::IsPresenceOfNode(entities)) + { + med_int nbProfile(MEDfield23nProfile(fid,nasc.getName().c_str(),getIteration(),getOrder(),MED_NODE,MED_NONE,meshCsit+1,meshName,pflName,locName)); + if(nbProfile>0) + { + _field_pm_pt.push_back(MEDFileFieldPerMeshPerType::NewOnRead(fid,this,ON_NODES,INTERP_KERNEL::NORM_ERROR,nasc,pd)); + setMeshName(MEDLoaderBase::buildStringFromFortran(meshName,MED_NAME_SIZE)); + } + } +} + + MEDFileFieldPerMesh::MEDFileFieldPerMesh(MEDFileAnyTypeField1TSWithoutSDA *fath, const MEDCouplingMesh *mesh):_father(fath) { copyTinyInfoFrom(mesh); diff --git a/src/MEDLoader/MEDFileFieldInternal.hxx b/src/MEDLoader/MEDFileFieldInternal.hxx index 0b61b61f6..138818998 100644 --- a/src/MEDLoader/MEDFileFieldInternal.hxx +++ b/src/MEDLoader/MEDFileFieldInternal.hxx @@ -342,6 +342,7 @@ namespace MEDCoupling public: static MEDFileFieldPerMesh *New(MEDFileAnyTypeField1TSWithoutSDA *fath, const MEDCouplingMesh *mesh); static MEDFileFieldPerMesh *NewOnRead(med_idt fid, MEDFileAnyTypeField1TSWithoutSDA *fath, int meshCsit, int meshIteration, int meshOrder, const MEDFileFieldNameScope& nasc, const MEDFileMesh *mm, const MEDFileEntities *entities); + static MEDFileFieldPerMesh *NewOnRead(med_idt fid, MEDFileAnyTypeField1TSWithoutSDA *fath, int meshCsit, int meshIteration, int meshOrder, const MEDFileFieldNameScope& nasc, const PartDefinition *pd, const MEDFileEntities *entities); std::string getClassName() const override { return std::string("MEDFileFieldPerMesh"); } std::size_t getHeapMemorySizeWithoutChildren() const; std::vector getDirectChildrenWithNull() const; @@ -413,6 +414,7 @@ namespace MEDCoupling std::vector& code, std::vector& notNullPfls); static mcIdType ComputeNbOfElems(const MEDFileFieldGlobsReal *glob, TypeOfField type, const std::vector& geoTypes, const std::vector< std::pair >& dads, const std::vector& locs); MEDFileFieldPerMesh(med_idt fid, MEDFileAnyTypeField1TSWithoutSDA *fath, int meshCsit, int meshIteration, int meshOrder, const MEDFileFieldNameScope& nasc, const MEDFileMesh *mm, const MEDFileEntities *entities); + MEDFileFieldPerMesh(med_idt fid, MEDFileAnyTypeField1TSWithoutSDA *fath, int meshCsit, int meshIteration, int meshOrder, const MEDFileFieldNameScope& nasc, const PartDefinition *pd, const MEDFileEntities *entities); MEDFileFieldPerMesh(MEDFileAnyTypeField1TSWithoutSDA *fath, const MEDCouplingMesh *mesh); MEDFileFieldPerMesh(MEDFileAnyTypeField1TSWithoutSDA *fath, const std::string& meshName, int meshIt, int meshOrd):_mesh_iteration(meshIt),_mesh_order(meshOrd),_father(fath) { } private: diff --git a/src/MEDLoader/MEDFileMesh.cxx b/src/MEDLoader/MEDFileMesh.cxx index 4f2bab937..a6e75b7be 100644 --- a/src/MEDLoader/MEDFileMesh.cxx +++ b/src/MEDLoader/MEDFileMesh.cxx @@ -2538,6 +2538,24 @@ MEDFileUMesh *MEDFileUMesh::LoadPartOf(med_idt fid, const std::string& mName, co return ret.retn(); } +/*! + * This method loads from file with name \a fileName a part of the mesh called \a mName as MEDFileUMesh::LoadPartOf does. The difference is that + * here we are not limited to slice of cells, but we can potentially load a random selection of cells, defined in the \a distrib vector. + * \param [in] fid - id of the file + * \param [in] mName - the name of the mesh to be read + * \param [in] distrib - map defining for each geometric type, the corresponding vector of cells we want to load with c-type indexing (starting from zero). + * \param [in] dt - the iteration, that is to say the first element of the pair that locates the asked time step. + * \param [in] it - the order, that is to say the second element of the pair that locates the asked time step. + * \param [in] mrs - the request for what to be loaded. + * \return MEDFileUMesh * - a new instance of MEDFileUMesh. The caller is to delete this mesh using decrRef() as it is no more needed. + */ +MEDFileUMesh *MEDFileUMesh::LoadPartOfFromUserDistrib(med_idt fid, const std::string& mName, const std::map>& distrib, int dt, int it, MEDFileMeshReadSelector *mrs) +{ + MCAuto ret(MEDFileUMesh::New()); + ret->loadPartUMeshFromFileFromUserDistrib(fid,mName,distrib,[](MEDFileUMeshL2& loader,med_idt fid, MeshOrStructMeshCls *mid,const std::string& mName,const std::map>& distrib,int dt,int it,MEDFileMeshReadSelector *mrs){ loader.loadPartFromUserDistrib(fid,mid,mName,distrib,dt,it,mrs); },dt,it,mrs); + return ret.retn(); +} + /*! * This method is an helper to load only consecutive nodes chunk of data of MED file pointed by \a fileName. * Consecutive chunk is specified classicaly by start (included) stop (excluded) format with \a startNodeId and \a stopNodeId respectively. @@ -2926,6 +2944,32 @@ std::function>& distrib, + std::function>&,int,int,MEDFileMeshReadSelector *)> functorOnUMeshL2, + int dt, int it, MEDFileMeshReadSelector *mrs) +{ + MEDFileUMeshL2 loaderl2; + MEDCoupling::MEDCouplingMeshType meshType; + int dummy0,dummy1; + std::string dummy2; + MEDCoupling::MEDCouplingAxisType dummy3; + INTERP_KERNEL::AutoCppPtr mid(MEDFileUMeshL2::GetMeshIdFromName(fid,mName,meshType,dummy3,dummy0,dummy1,dummy2)); + if(meshType!=UNSTRUCTURED) + { + std::ostringstream oss; oss << "loadPartUMeshFromFileFromUserDistrib : Trying to load as unstructured an existing mesh with name '" << mName << "' !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + functorOnUMeshL2(loaderl2,fid,mid,mName,distrib,dt,it,mrs); + dispatchLoadedPart(fid,loaderl2,mName,mrs); +} + + /*! * \brief Write joints in a file */ diff --git a/src/MEDLoader/MEDFileMesh.hxx b/src/MEDLoader/MEDFileMesh.hxx index 69e02e815..690c3dc34 100644 --- a/src/MEDLoader/MEDFileMesh.hxx +++ b/src/MEDLoader/MEDFileMesh.hxx @@ -273,6 +273,7 @@ namespace MEDCoupling MEDLOADER_EXPORT static MCAuto LoadConnectivityOnlyPartOf(med_idt fid, const std::string& mName, const std::vector& types, const std::vector& slicPerTyp, int dt=-1, int it=-1, MEDFileMeshReadSelector *mrs=nullptr); MEDLOADER_EXPORT static MEDFileUMesh *LoadPartOf(const std::string& fileName, const std::string& mName, const std::vector& types, const std::vector& slicPerTyp, int dt=-1, int it=-1, MEDFileMeshReadSelector *mrs=nullptr); MEDLOADER_EXPORT static MEDFileUMesh *LoadPartOf(med_idt fid, const std::string& mName, const std::vector& types, const std::vector& slicPerTyp, int dt=-1, int it=-1, MEDFileMeshReadSelector *mrs=nullptr); + MEDLOADER_EXPORT static MEDFileUMesh *LoadPartOfFromUserDistrib(med_idt fid, const std::string& mName, const std::map>& distrib, int dt=-1, int it=-1, MEDFileMeshReadSelector *mrs=0); MEDLOADER_EXPORT static void LoadPartCoords(const std::string& fileName, const std::string& mName, int dt, int it, const std::vector& infosOnComp, mcIdType startNodeId, mcIdType stopNodeId, MCAuto& coords, MCAuto& partCoords, MCAuto& famCoords, MCAuto& numCoords, MCAuto& nameCoords); MEDLOADER_EXPORT static const char *GetSpeStr4ExtMesh() { return SPE_FAM_STR_EXTRUDED_MESH; } @@ -384,6 +385,7 @@ MCAuto& coords, MCAuto& partCoords, MCAuto& types, const std::vector& slicPerTyp, std::function& types, const std::vector&,int,int,MEDFileMeshReadSelector *)> functorOnUMeshL2, int dt=-1, int it=-1, MEDFileMeshReadSelector *mrs=0); + void loadPartUMeshFromFileFromUserDistrib(med_idt fid, const std::string& mName, const std::map>& distrib, std::function>&,int,int,MEDFileMeshReadSelector *)> functorOnUMeshL2, int dt=-1, int it=-1, MEDFileMeshReadSelector *mrs=0); void loadLL(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs); void dispatchLoadedPart(med_idt fid, const MEDFileUMeshL2& loaderl2, const std::string& mName, MEDFileMeshReadSelector *mrs); const MEDFileUMeshSplitL1 *getMeshAtLevSafe(int meshDimRelToMaxExt) const; @@ -394,6 +396,7 @@ MCAuto& coords, MCAuto& partCoords, MCAuto > getAllNonNullFamilyIds() const; MCAuto& checkAndGiveEntryInSplitL1(int meshDimRelToMax, MEDCouplingPointSet *m); + private: static const char SPE_FAM_STR_EXTRUDED_MESH[]; private: diff --git a/src/MEDLoader/MEDFileMeshElt.cxx b/src/MEDLoader/MEDFileMeshElt.cxx index c61e94d0a..a36397d1d 100644 --- a/src/MEDLoader/MEDFileMeshElt.cxx +++ b/src/MEDLoader/MEDFileMeshElt.cxx @@ -29,8 +29,11 @@ #include "InterpKernelAutoPtr.hxx" #include "CellModel.hxx" +#include "MEDFilterEntity.hxx" + #include + // From MEDLOader.cxx TU extern med_geometry_type typmai3[INTERP_KERNEL::NORM_MAXTYPE]; @@ -106,6 +109,7 @@ MEDFileUMeshPerType *MEDFileUMeshPerType::New(med_idt fid, const char *mName, in return new MEDFileUMeshPerType(fid,mName,dt,it,mdim,geoElt,geoElt2,whichEntity,mrs); } + MEDFileUMeshPerType *MEDFileUMeshPerType::NewPart(med_idt fid, const char *mName, int dt, int it, int mdim, INTERP_KERNEL::NormalizedCellType geoElt2, mcIdType strt, mcIdType stp, mcIdType step, MEDFileMeshReadSelector *mrs) { int geoElt2i((int)geoElt2); @@ -120,6 +124,20 @@ MEDFileUMeshPerType *MEDFileUMeshPerType::NewPart(med_idt fid, const char *mName return ret.retn(); } +MEDFileUMeshPerType *MEDFileUMeshPerType::NewPart(med_idt fid, const char *mName, int dt, int it, int mdim, INTERP_KERNEL::NormalizedCellType geoElt2, const std::vector& distrib, MEDFileMeshReadSelector *mrs) +{ + int geoElt2i((int)geoElt2); + if(geoElt2i<0 || geoElt2i>=INTERP_KERNEL::NORM_MAXTYPE) + throw INTERP_KERNEL::Exception("MEDFileUMeshPerType::NewPart : Not recognized MEDCoupling/MEDLoader geometric type !"); + med_geometry_type geoElt(typmai3[geoElt2]); + med_entity_type whichEntity; + if(!isExisting(fid,mName,dt,it,geoElt,whichEntity)) + throw INTERP_KERNEL::Exception("MEDFileUMeshPerType::NewPart : The specified geo type is not present in the specified mesh !"); + MCAuto ret(new MEDFileUMeshPerType); + ret->loadPart(fid,mName,dt,it,mdim,geoElt,geoElt2,whichEntity,distrib,mrs); + return ret.retn(); +} + std::size_t MEDFileUMeshPerType::getHeapMemorySizeWithoutChildren() const { return MEDFileUMeshPerTypeCommon::getHeapMemorySizeWithoutChildren()+0; @@ -180,6 +198,23 @@ MEDFileUMeshPerType::MEDFileUMeshPerType(med_idt fid, const char *mName, int dt, loadPolyh(fid,mName,dt,it,mdim,curNbOfElem,geoElt,entity,mrs); } +void MEDFileUMeshPerType::loadPart(med_idt fid, const char *mName, int dt, int it, int mdim, med_geometry_type geoElt, INTERP_KERNEL::NormalizedCellType type, + med_entity_type entity, const std::vector& distrib, MEDFileMeshReadSelector *mrs) +{ + med_bool changement,transformation; + mcIdType curNbOfElem(MEDmeshnEntity(fid,mName,dt,it,entity,geoElt,MED_CONNECTIVITY,MED_NODAL,&changement,&transformation)); + const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type)); + MCAuto listOfIds=DataArrayIdType::New(); + listOfIds->useArray(distrib.data(),false,DeallocType::C_DEALLOC,distrib.size(),1); + _pd=PartDefinition::New(listOfIds); + if(!cm.isDynamic()) + { + loadPartStaticType(fid,mName,dt,it,mdim,curNbOfElem,geoElt,type,entity,mrs); + } + else + throw INTERP_KERNEL::Exception("MEDFileUMeshPerType::loadPart : not implemented yet for the dynamic type !"); +} + void MEDFileUMeshPerType::loadPart(med_idt fid, const char *mName, int dt, int it, int mdim, med_geometry_type geoElt, INTERP_KERNEL::NormalizedCellType type, med_entity_type entity, mcIdType strt, mcIdType end, mcIdType step, MEDFileMeshReadSelector *mrs) { @@ -189,12 +224,13 @@ void MEDFileUMeshPerType::loadPart(med_idt fid, const char *mName, int dt, int i _pd=PartDefinition::New(strt,end,step); if(!cm.isDynamic()) { - loadPartStaticType(fid,mName,dt,it,mdim,curNbOfElem,geoElt,type,entity,strt,end,step,mrs); + loadPartStaticType(fid,mName,dt,it,mdim,curNbOfElem,geoElt,type,entity,mrs); } else throw INTERP_KERNEL::Exception("MEDFileUMeshPerType::loadPart : not implemented yet for the dynamic type !"); } + void MEDFileUMeshPerType::loadFromStaticType(med_idt fid, const char *mName, int dt, int it, int mdim, mcIdType curNbOfElem, med_geometry_type geoElt, INTERP_KERNEL::NormalizedCellType type, med_entity_type entity, MEDFileMeshReadSelector *mrs) { @@ -210,50 +246,49 @@ void MEDFileUMeshPerType::loadFromStaticType(med_idt fid, const char *mName, int } void MEDFileUMeshPerType::loadPartStaticType(med_idt fid, const char *mName, int dt, int it, int mdim, mcIdType curNbOfElem, med_geometry_type geoElt, INTERP_KERNEL::NormalizedCellType type, - med_entity_type entity, mcIdType strt, mcIdType end, mcIdType step, MEDFileMeshReadSelector *mrs) + med_entity_type entity, MEDFileMeshReadSelector *mrs) { - if(strt<0) - throw INTERP_KERNEL::Exception("MEDFileUMeshPerType::loadPartStaticType : start pos is negative !"); - if(end>curNbOfElem) - throw INTERP_KERNEL::Exception("MEDFileUMeshPerType::loadPartStaticType : end is after the authorized range !"); - mcIdType nbOfEltsToLoad(DataArray::GetNumberOfItemGivenBES(strt,end,step,"MEDFileUMeshPerType::loadPartStaticType")); _m=MEDCoupling1SGTUMesh::New(mName,type); MEDCoupling1SGTUMesh *mc(dynamic_cast((MEDCoupling1GTUMesh *)_m)); MCAuto conn(DataArrayMedInt::New()); mcIdType nbOfNodesPerCell(mc->getNumberOfNodesPerCell()); + if(!_pd) + throw INTERP_KERNEL::Exception("MEDFileUMeshPerType::loadPartStaticType : no part definition !"); + mcIdType nbOfEltsToLoad(_pd->getNumberOfElems()); conn->alloc(nbOfNodesPerCell*nbOfEltsToLoad,1); - med_filter filter=MED_FILTER_INIT; - MEDfilterBlockOfEntityCr(fid,/*nentity*/ToMedInt(curNbOfElem),/*nvaluesperentity*/1,/*nconstituentpervalue*/ToMedInt(nbOfNodesPerCell), - MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, - /*start*/ToMedInt(strt+1),/*stride*/ToMedInt(step),/*count*/1,/*blocksize*/ToMedInt(nbOfEltsToLoad), - /*lastblocksize=useless because count=1*/0,&filter); - MEDFILESAFECALLERRD0(MEDmeshElementConnectivityAdvancedRd,(fid,mName,dt,it,entity,geoElt,MED_NODAL,&filter,conn->getPointer())); - MEDfilterClose(&filter); + { + MEDFilterEntity filter; + filter.fill(fid,/*nentity*/curNbOfElem,/*nvaluesperentity*/1,/*nconstituentpervalue*/nbOfNodesPerCell, + MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, + _pd); + MEDFILESAFECALLERRD0(MEDmeshElementConnectivityAdvancedRd,(fid,mName,dt,it,entity,geoElt,MED_NODAL,filter.getPtr(),conn->getPointer())); + } std::transform(conn->begin(),conn->end(),conn->getPointer(),std::bind(std::plus(),std::placeholders::_1,-1)); mc->setNodalConnectivity(FromMedIntArray(conn)); - loadPartOfCellCommonPart(fid,mName,strt,end,step,dt,it,mdim,curNbOfElem,geoElt,entity,mrs); + loadPartOfCellCommonPart(fid,mName,dt,it,mdim,curNbOfElem,geoElt,entity,mrs); } -void MEDFileUMeshPerType::loadPartOfCellCommonPart(med_idt fid, const char *mName, mcIdType strt, mcIdType stp, mcIdType step, int dt, int it, int mdim, mcIdType curNbOfElem, med_geometry_type geoElt, med_entity_type entity, MEDFileMeshReadSelector *mrs) + +void MEDFileUMeshPerType::loadPartOfCellCommonPart(med_idt fid, const char *mName, int dt, int it, int mdim, mcIdType curNbOfElem, med_geometry_type geoElt, med_entity_type entity, MEDFileMeshReadSelector *mrs) { med_bool changement,transformation; + if(!_pd) + throw INTERP_KERNEL::Exception("MEDFileUMeshPerType::loadPartOfCellCommonPart : no part definition !"); + mcIdType nbOfEltsToLoad(_pd->getNumberOfElems()); _fam=0; - mcIdType nbOfEltsToLoad(DataArray::GetNumberOfItemGivenBES(strt,stp,step,"MEDFileUMeshPerType::loadPartOfCellCommonPart")); if(MEDmeshnEntity(fid,mName,dt,it,entity,geoElt,MED_FAMILY_NUMBER,MED_NODAL,&changement,&transformation)>0) { if(!mrs || mrs->isCellFamilyFieldReading()) { MCAuto miFam(DataArrayMedInt::New()); miFam->alloc(nbOfEltsToLoad,1); - med_filter filter=MED_FILTER_INIT; - MEDfilterBlockOfEntityCr(fid,/*nentity*/ToMedInt(curNbOfElem),/*nvaluesperentity*/1,/*nconstituentpervalue*/1, - MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, - /*start*/ToMedInt(strt+1),/*stride*/ToMedInt(step),/*count*/1,/*blocksize*/ToMedInt(nbOfEltsToLoad), - /*lastblocksize=useless because count=1*/0,&filter); - if(MEDmeshEntityAttributeAdvancedRd(fid,mName,MED_FAMILY_NUMBER,dt,it,entity,geoElt,&filter,miFam->getPointer())!=0) + MEDFilterEntity filter; + filter.fill(fid,/*nentity*/curNbOfElem,/*nvaluesperentity*/1,/*nconstituentpervalue*/1, + MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, + _pd); + if(MEDmeshEntityAttributeAdvancedRd(fid,mName,MED_FAMILY_NUMBER,dt,it,entity,geoElt,filter.getPtr(),miFam->getPointer())!=0) miFam->fillWithZero(); _fam=FromMedIntArray(miFam); - MEDfilterClose(&filter); } } _num=0; @@ -263,15 +298,13 @@ void MEDFileUMeshPerType::loadPartOfCellCommonPart(med_idt fid, const char *mNam { MCAuto miNum(DataArrayMedInt::New()); miNum->alloc(nbOfEltsToLoad,1); - med_filter filter=MED_FILTER_INIT; - MEDfilterBlockOfEntityCr(fid,/*nentity*/ToMedInt(curNbOfElem),/*nvaluesperentity*/1,/*nconstituentpervalue*/1, - MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, - /*start*/ToMedInt(strt+1),/*stride*/ToMedInt(step),/*count*/1,/*blocksize*/ToMedInt(nbOfEltsToLoad), - /*lastblocksize=useless because count=1*/0,&filter); - if(MEDmeshEntityAttributeAdvancedRd(fid,mName,MED_NUMBER,dt,it,entity,geoElt,&filter,miNum->getPointer())!=0) + MEDFilterEntity filter; + filter.fill(fid,/*nentity*/curNbOfElem,/*nvaluesperentity*/1,/*nconstituentpervalue*/1, + MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, + _pd); + if(MEDmeshEntityAttributeAdvancedRd(fid,mName,MED_NUMBER,dt,it,entity,geoElt,filter.getPtr(),miNum->getPointer())!=0) miNum->fillWithZero(); _num=FromMedIntArray(miNum); - MEDfilterClose(&filter); } } _names=0; @@ -281,16 +314,14 @@ void MEDFileUMeshPerType::loadPartOfCellCommonPart(med_idt fid, const char *mNam { _names=DataArrayAsciiChar::New(); _names->alloc(nbOfEltsToLoad+1,MED_SNAME_SIZE);//not a bug to avoid the memory corruption due to last \0 at the end - med_filter filter=MED_FILTER_INIT; - MEDfilterBlockOfEntityCr(fid,/*nentity*/ToMedInt(curNbOfElem),/*nvaluesperentity*/1,/*nconstituentpervalue*/1, - MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, - /*start*/ToMedInt(strt+1),/*stride*/ToMedInt(step),/*count*/1,/*blocksize*/ToMedInt(nbOfEltsToLoad), - /*lastblocksize=useless because count=1*/0,&filter); - if(MEDmeshEntityAttributeAdvancedRd(fid,mName,MED_NAME,dt,it,entity,geoElt,&filter,_names->getPointer())!=0) + MEDFilterEntity filter; + filter.fill(fid,/*nentity*/curNbOfElem,/*nvaluesperentity*/1,/*nconstituentpervalue*/1, + MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, + _pd); + if(MEDmeshEntityAttributeAdvancedRd(fid,mName,MED_NAME,dt,it,entity,geoElt,filter.getPtr(),_names->getPointer())!=0) _names=0; else _names->reAlloc(nbOfEltsToLoad);//not a bug to avoid the memory corruption due to last \0 at the end - MEDfilterClose(&filter); } } } diff --git a/src/MEDLoader/MEDFileMeshElt.hxx b/src/MEDLoader/MEDFileMeshElt.hxx index 746a0a9b8..cc65f166d 100644 --- a/src/MEDLoader/MEDFileMeshElt.hxx +++ b/src/MEDLoader/MEDFileMeshElt.hxx @@ -58,6 +58,8 @@ namespace MEDCoupling public: static MEDFileUMeshPerType *New(med_idt fid, const char *mName, int dt, int it, int mdim, med_geometry_type geoElt, INTERP_KERNEL::NormalizedCellType geoElt2, MEDFileMeshReadSelector *mrs); static MEDFileUMeshPerType *NewPart(med_idt fid, const char *mName, int dt, int it, int mdim, INTERP_KERNEL::NormalizedCellType geoElt2, mcIdType strt, mcIdType stp, mcIdType step, MEDFileMeshReadSelector *mrs); + static MEDFileUMeshPerType *NewPart(med_idt fid, const char *mName, int dt, int it, int mdim, INTERP_KERNEL::NormalizedCellType geoElt2, const std::vector& distrib, MEDFileMeshReadSelector *mrs); + std::string getClassName() const override { return std::string("MEDFileUMeshPerType"); } static bool isExisting(med_idt fid, const char *mName, int dt, int it, med_geometry_type geoElt, med_entity_type& whichEntity); std::size_t getHeapMemorySizeWithoutChildren() const; @@ -72,19 +74,21 @@ namespace MEDCoupling med_entity_type entity, MEDFileMeshReadSelector *mrs); void loadPart(med_idt fid, const char *mName, int dt, int it, int mdim, med_geometry_type geoElt, INTERP_KERNEL::NormalizedCellType type, med_entity_type entity, mcIdType strt, mcIdType end, mcIdType step, MEDFileMeshReadSelector *mrs); + void loadPart(med_idt fid, const char *mName, int dt, int it, int mdim, med_geometry_type geoElt, INTERP_KERNEL::NormalizedCellType type, + med_entity_type entity, const std::vector& distrib, MEDFileMeshReadSelector *mrs); void loadFromStaticType(med_idt fid, const char *mName, int dt, int it, int mdim, mcIdType curNbOfElem, med_geometry_type geoElt, INTERP_KERNEL::NormalizedCellType type, med_entity_type entity, MEDFileMeshReadSelector *mrs); void loadPartStaticType(med_idt fid, const char *mName, int dt, int it, int mdim, mcIdType curNbOfElem, med_geometry_type geoElt, INTERP_KERNEL::NormalizedCellType type, - med_entity_type entity, mcIdType strt, mcIdType end, mcIdType step, MEDFileMeshReadSelector *mrs); + med_entity_type entity, MEDFileMeshReadSelector *mrs); void loadPolyg(med_idt fid, const char *mName, int dt, int it, int mdim, mcIdType arraySize, med_geometry_type geoElt, med_entity_type entity, MEDFileMeshReadSelector *mrs); void loadPolyh(med_idt fid, const char *mName, int dt, int it, int mdim, mcIdType connFaceLgth, med_geometry_type geoElt, med_entity_type entity, MEDFileMeshReadSelector *mrs); - void loadPartOfCellCommonPart(med_idt fid, const char *mName, mcIdType strt, mcIdType stp, mcIdType step, int dt, int it, int mdim, mcIdType curNbOfElem, med_geometry_type geoElt, med_entity_type entity, MEDFileMeshReadSelector *mrs); + void loadPartOfCellCommonPart(med_idt fid, const char *mName, int dt, int it, int mdim, mcIdType curNbOfElem, med_geometry_type geoElt, med_entity_type entity, MEDFileMeshReadSelector *mrs); + private: MCAuto _m; MCAuto _pd; }; } - #endif diff --git a/src/MEDLoader/MEDFileMeshLL.cxx b/src/MEDLoader/MEDFileMeshLL.cxx index 18d3e5931..5ef1d0b83 100644 --- a/src/MEDLoader/MEDFileMeshLL.cxx +++ b/src/MEDLoader/MEDFileMeshLL.cxx @@ -31,6 +31,7 @@ #include "InterpKernelAutoPtr.hxx" #include "CellModel.hxx" +#include "MEDFilterEntity.hxx" #include #include @@ -602,6 +603,52 @@ void MEDFileUMeshL2::loadPart(med_idt fid, const MeshOrStructMeshCls *mId, const dealWithCoordsInLoadPart(fid,mId,mName,infosOnComp,types,slicPerTyp,dt,it,mrs); } +/*! + * This method loads from file \a fid a part of the mesh (made of same geometrical type cells \a type) called \a mName. The loading is done in 2 steps: + * First, we load the connectivity of nodes. + * Second, we load coordinates of nodes lying in the specified cells (same as MEDFileUMeshL2::dealWithCoordsInLoadPart, except in this case, we're not limited to slice of nodes) + * \throw exception if multiple load sessions are requested + */ +void MEDFileUMeshL2::loadPartFromUserDistrib(med_idt fid, const MeshOrStructMeshCls *mId, const std::string& mName, const std::map>& distrib, int dt, int it, MEDFileMeshReadSelector *mrs) +{ + int Mdim; + std::vector infosOnComp(loadCommonPart(fid,mId,mName,dt,it,Mdim)); + if(Mdim==-4) + return ; + + /* First step : loading connectivity of nodes, ie building a new mesh of one geometrical type with only the specified cells in distrib */ + loadPartOfConnectivityFromUserDistrib(fid,Mdim,mName,distrib,dt,it,mrs); + + /* Second step : loading nodes */ + med_bool changement,transformation; + mcIdType nCoords(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,MED_COORDINATE,MED_NO_CMODE,&changement,&transformation)); + std::vector fetchedNodeIds(nCoords,false); + for(std::vector< std::vector< MCAuto > >::const_iterator it0=_per_type_mesh.begin();it0!=_per_type_mesh.end();it0++) + for(std::vector< MCAuto >::const_iterator it1=(*it0).begin();it1!=(*it0).end();it1++) + (*it1)->getMesh()->computeNodeIdsAlg(fetchedNodeIds); // for each node in the original mesh, which ones are laying on the current single geometrical type partial mesh + + if(!mrs || mrs->getNumberOfCoordsLoadSessions()==1) + { + // renumbering nodes inside the connectivity of the partial mesh: + // until now, the numbering used in the connectivity of the cells was that of the integral mesh, + // so it might be sparsed as some original nodes are missing in the partial mesh, + // thus we want each node to be renumbered so that the sequence of their numbers form a range + MCAuto fni(DataArrayIdType::BuildListOfSwitchedOn(fetchedNodeIds)); + MCAuto< MapKeyVal > o2n(fni->invertArrayN2O2O2NOptimized()); + for(std::vector< std::vector< MCAuto > >::const_iterator it0=_per_type_mesh.begin();it0!=_per_type_mesh.end();it0++) + for(std::vector< MCAuto >::const_iterator it1=(*it0).begin();it1!=(*it0).end();it1++) + (*it1)->getMesh()->renumberNodesInConn(o2n->data()); + + // loading coordinates of fetched nodes + std::vector distribNodes; + for(std::map::const_iterator mapIter = o2n->data().begin(); mapIter != o2n->data().end(); ++mapIter) + distribNodes.push_back(mapIter->first); + this->loadPartCoords(fid,infosOnComp,mName,dt,it,distribNodes); + } + else + throw INTERP_KERNEL::Exception("MEDFileUMeshL2::loadPartFromUserDistrib: multiple load sessions not handled!"); +} + void MEDFileUMeshL2::loadConnectivity(med_idt fid, int mdim, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs) { _per_type_mesh.resize(1); @@ -634,6 +681,23 @@ void MEDFileUMeshL2::loadPartOfConnectivity(med_idt fid, int mdim, const std::st sortTypes(); } +/*! + * This method builds a new mesh of single geometrical type based on the partition of cells \a distrib, from mesh \a mName in file \a fid. + * This distribution is not necessarily a slice. + */ +void MEDFileUMeshL2::loadPartOfConnectivityFromUserDistrib(med_idt fid, int mdim, const std::string& mName, const std::map>& distrib, int dt, int it, MEDFileMeshReadSelector *mrs) +{ + _per_type_mesh.resize(1); + _per_type_mesh[0].clear(); + std::map>::const_iterator iter; + for (iter = distrib.begin(); iter != distrib.end(); iter++) + { + MCAuto tmp(MEDFileUMeshPerType::NewPart(fid,mName.c_str(),dt,it,mdim,iter->first/*type*/,iter->second/*distrib over the current type*/,mrs)); + _per_type_mesh[0].push_back(tmp); + } + sortTypes(); +} + void MEDFileUMeshL2::loadCoords(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it) { int spaceDim((int)infosOnComp.size()); @@ -682,55 +746,108 @@ void MEDFileUMeshL2::loadCoords(med_idt fid, const std::vector& inf _coords->setInfoOnComponent(i,infosOnComp[i]); } + +void MEDFileUMeshL2::LoadPartCoords(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it, const std::vector& distribNodes, +MCAuto& _coords, MCAuto& _part_coords, MCAuto& _fam_coords, MCAuto& _num_coords, MCAuto& _name_coords) +{ + med_int spaceDim((int)infosOnComp.size()); + allocCoordsPartCoords(spaceDim,distribNodes,_coords,_part_coords); + _coords->setInfoOnComponents(infosOnComp); + fillPartCoords(fid,spaceDim,mName,dt,it,_part_coords,_coords,_fam_coords,_num_coords,_name_coords); +} + void MEDFileUMeshL2::LoadPartCoords(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it, mcIdType nMin, mcIdType nMax, MCAuto& _coords, MCAuto& _part_coords, MCAuto& _fam_coords, MCAuto& _num_coords, MCAuto& _name_coords) { - med_bool changement,transformation; - med_int spaceDim((int)infosOnComp.size()),nCoords(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,MED_COORDINATE,MED_NO_CMODE,&changement,&transformation)); + med_int spaceDim((int)infosOnComp.size()); + allocCoordsPartCoords(spaceDim,nMin,nMax,_coords,_part_coords); + _coords->setInfoOnComponents(infosOnComp); + fillPartCoords(fid,spaceDim,mName,dt,it,_part_coords,_coords,_fam_coords,_num_coords,_name_coords); +} + +/*! + * This method allocates the space needed to load coordinates of nodes specified in the vector \a nodeIds and creates a PartDefinition object to store the ids in \a nodeIds + */ +void MEDFileUMeshL2::allocCoordsPartCoords(mcIdType spaceDim, const std::vector& nodeIds, MCAuto& _coords, MCAuto& _part_coords) +{ + mcIdType nbNodesToLoad(nodeIds.size()); + _coords=DataArrayDouble::New(); + _coords->alloc(nbNodesToLoad,spaceDim); + + MCAuto nodeIdsArray=DataArrayIdType::New(); + nodeIdsArray->useArray(nodeIds.data(),false,DeallocType::C_DEALLOC,nbNodesToLoad,1); + _part_coords=PartDefinition::New(nodeIdsArray); +} + +/*! + * This method allocates the space needed to load coordinates of all nodes between \a nMin and \a nMax and creates a PartDefinition object to store them + */ +void MEDFileUMeshL2::allocCoordsPartCoords(mcIdType spaceDim, mcIdType nMin, mcIdType nMax, MCAuto& _coords, MCAuto& _part_coords) +{ _coords=DataArrayDouble::New(); mcIdType nbNodesToLoad(nMax-nMin); _coords->alloc(nbNodesToLoad,spaceDim); - med_filter filter=MED_FILTER_INIT,filter2=MED_FILTER_INIT; - MEDfilterBlockOfEntityCr(fid,/*nentity*/nCoords,/*nvaluesperentity*/1,/*nconstituentpervalue*/spaceDim, - MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, - /*start*/ToMedInt(nMin+1),/*stride*/1,/*count*/1,/*blocksize*/ToMedInt(nbNodesToLoad), - /*lastblocksize=useless because count=1*/0,&filter); - MEDFILESAFECALLERRD0(MEDmeshNodeCoordinateAdvancedRd,(fid,mName.c_str(),dt,it,&filter,_coords->getPointer())); + _part_coords=PartDefinition::New(nMin,nMax,1); - MEDfilterClose(&filter); - MEDfilterBlockOfEntityCr(fid,nCoords,1,1,MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE, - MED_NO_PROFILE,ToMedInt(nMin+1),1,1,ToMedInt(nbNodesToLoad),0,&filter2); - if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_FAMILY_NUMBER,MED_NODAL,&changement,&transformation)>0) - { - MCAuto miFamCoord=DataArrayMedInt::New(); - miFamCoord->alloc(nbNodesToLoad,1); - MEDFILESAFECALLERRD0(MEDmeshEntityAttributeAdvancedRd,(fid,mName.c_str(),MED_FAMILY_NUMBER,dt,it,MED_NODE,MED_NO_GEOTYPE,&filter2,miFamCoord->getPointer())); - _fam_coords=FromMedIntArray(miFamCoord); - } - else - _fam_coords=nullptr; - if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_NUMBER,MED_NODAL,&changement,&transformation)>0) - { - MCAuto miNumCoord=DataArrayMedInt::New(); - miNumCoord->alloc(nbNodesToLoad,1); - MEDFILESAFECALLERRD0(MEDmeshEntityAttributeAdvancedRd,(fid,mName.c_str(),MED_NUMBER,dt,it,MED_NODE,MED_NO_GEOTYPE,&filter2,miNumCoord->getPointer())); - _num_coords=FromMedIntArray(miNumCoord); - } - else - _num_coords=nullptr; - if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_NAME,MED_NODAL,&changement,&transformation)>0) - { - _name_coords=DataArrayAsciiChar::New(); - _name_coords->alloc(nbNodesToLoad+1,MED_SNAME_SIZE);//not a bug to avoid the memory corruption due to last \0 at the end - MEDFILESAFECALLERRD0(MEDmeshEntityAttributeAdvancedRd,(fid,mName.c_str(),MED_NAME,dt,it,MED_NODE,MED_NO_GEOTYPE,&filter2,_name_coords->getPointer())); - _name_coords->reAlloc(nbNodesToLoad);//not a bug to avoid the memory corruption due to last \0 at the end - } - else - _name_coords=nullptr; - MEDfilterClose(&filter2); - _coords->setInfoOnComponents(infosOnComp); } +/*! + * This method loads coordinates of every node in \a partCoords and additionnal low-level information + */ +void MEDFileUMeshL2::fillPartCoords(med_idt fid, mcIdType spaceDim, const std::string& mName, int dt, int it, const PartDefinition *partCoords, + MCAuto& _coords, MCAuto& _fam_coords, MCAuto& _num_coords, MCAuto& _name_coords) +{ + med_bool changement,transformation; + med_int nCoords(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,MED_COORDINATE,MED_NO_CMODE,&changement,&transformation)); + mcIdType nbNodesToLoad = partCoords->getNumberOfElems(); + + // Based on the ids in \a partCoords, defining the appropriate med_filter (filter of block if the ids form a slice, a generic filter otherwise) + { + MEDFilterEntity filter1; + filter1.fill(fid,/*nentity*/nCoords,/*nvaluesperentity*/1,/*nconstituentpervalue*/spaceDim, + MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, + partCoords); + // With the filter defined above, retrieve coordinates of nodes + MEDFILESAFECALLERRD0(MEDmeshNodeCoordinateAdvancedRd,(fid,mName.c_str(),dt,it,filter1.getPtr(),_coords->getPointer())); + } + + { + MEDFilterEntity filter2; + filter2.fill(fid,nCoords,1,1, + MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, partCoords); + + // Retrieve additional information regarding nodes + if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_FAMILY_NUMBER,MED_NODAL,&changement,&transformation)>0) + { + MCAuto miFamCoord=DataArrayMedInt::New(); + miFamCoord->alloc(nbNodesToLoad,1); + MEDFILESAFECALLERRD0(MEDmeshEntityAttributeAdvancedRd,(fid,mName.c_str(),MED_FAMILY_NUMBER,dt,it,MED_NODE,MED_NO_GEOTYPE,filter2.getPtr(),miFamCoord->getPointer())); + _fam_coords=FromMedIntArray(miFamCoord); + } + else + _fam_coords=nullptr; + if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_NUMBER,MED_NODAL,&changement,&transformation)>0) + { + MCAuto miNumCoord=DataArrayMedInt::New(); + miNumCoord->alloc(nbNodesToLoad,1); + MEDFILESAFECALLERRD0(MEDmeshEntityAttributeAdvancedRd,(fid,mName.c_str(),MED_NUMBER,dt,it,MED_NODE,MED_NO_GEOTYPE,filter2.getPtr(),miNumCoord->getPointer())); + _num_coords=FromMedIntArray(miNumCoord); + } + else + _num_coords=nullptr; + if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_NAME,MED_NODAL,&changement,&transformation)>0) + { + _name_coords=DataArrayAsciiChar::New(); + _name_coords->alloc(nbNodesToLoad+1,MED_SNAME_SIZE);//not a bug to avoid the memory corruption due to last \0 at the end + MEDFILESAFECALLERRD0(MEDmeshEntityAttributeAdvancedRd,(fid,mName.c_str(),MED_NAME,dt,it,MED_NODE,MED_NO_GEOTYPE,filter2.getPtr(),_name_coords->getPointer())); + _name_coords->reAlloc(nbNodesToLoad);//not a bug to avoid the memory corruption due to last \0 at the end + } + else + _name_coords=nullptr; + } // filter2 +} + + /*! * For performance reasons LoadPartCoordsArray method calls LoadPartCoords */ @@ -765,6 +882,12 @@ void MEDFileUMeshL2::loadPartCoords(med_idt fid, const std::vector& LoadPartCoords(fid,infosOnComp,mName,dt,it,nMin,nMax,_coords,_part_coords,_fam_coords,_num_coords,_name_coords); } +void MEDFileUMeshL2::loadPartCoords(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it, const std::vector& distribNodes) +{ + LoadPartCoords(fid,infosOnComp,mName,dt,it,distribNodes,_coords,_part_coords,_fam_coords,_num_coords,_name_coords); +} + + void MEDFileUMeshL2::loadPartCoordsSlice(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it, const DataArrayIdType *nodeIds, mcIdType nbOfCoordLS) { nodeIds->checkAllocated(); diff --git a/src/MEDLoader/MEDFileMeshLL.hxx b/src/MEDLoader/MEDFileMeshLL.hxx index 94a34a2d1..38fe9b954 100644 --- a/src/MEDLoader/MEDFileMeshLL.hxx +++ b/src/MEDLoader/MEDFileMeshLL.hxx @@ -121,12 +121,16 @@ namespace MEDCoupling std::vector loadCommonPart(med_idt fid, const MeshOrStructMeshCls *mId, const std::string& mName, int dt, int it, int& Mdim); void loadAll(med_idt fid, const MeshOrStructMeshCls *mId, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs); void loadPart(med_idt fid, const MeshOrStructMeshCls *mId, const std::string& mName, const std::vector& types, const std::vector& slicPerTyp, int dt, int it, MEDFileMeshReadSelector *mrs); + void loadPartFromUserDistrib(med_idt fid, const MeshOrStructMeshCls *mId, const std::string& mName, const std::map>& distrib, int dt, int it, MEDFileMeshReadSelector *mrs); void dealWithCoordsInLoadPart(med_idt fid, const MeshOrStructMeshCls *mId, const std::string& mName, const std::vector& infosOnComp, const std::vector& types, const std::vector& slicPerTyp, int dt, int it, MEDFileMeshReadSelector *mrs); std::vector loadPartConnectivityOnly(med_idt fid, const MeshOrStructMeshCls *mId, const std::string& mName, const std::vector& types, const std::vector& slicPerTyp, int dt, int it, MEDFileMeshReadSelector *mrs, int& Mdim); void loadConnectivity(med_idt fid, int mdim, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs); void loadPartOfConnectivity(med_idt fid, int mdim, const std::string& mName, const std::vector& types, const std::vector& slicPerTyp, int dt, int it, MEDFileMeshReadSelector *mrs); + void loadPartOfConnectivityFromUserDistrib(med_idt fid, int mdim, const std::string& mName, const std::map>& distrib, int dt, int it, MEDFileMeshReadSelector *mrs); + void loadCoords(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it); void loadPartCoords(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it, mcIdType nMin, mcIdType nMax); + void loadPartCoords(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it, const std::vector& distribNodes); void loadPartCoordsSlice(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it, const DataArrayIdType *nodeIds, mcIdType nbOfCoordLS); int getNumberOfLevels() const { return (int)_per_type_mesh.size(); } bool emptyLev(int levId) const { return _per_type_mesh[levId].empty(); } @@ -140,10 +144,15 @@ namespace MEDCoupling MCAuto getCoordsGlobalNum() const { return _global_num_coords; } MCAuto getCoordsName() const { return _name_coords; } static void WriteCoords(med_idt fid, const std::string& mname, int dt, int it, double time, const DataArrayDouble *coords, const DataArrayIdType *famCoords, const DataArrayIdType *numCoords, const DataArrayAsciiChar *nameCoords, const DataArrayIdType *globalNumCoords); + static void LoadPartCoords(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it, const std::vector& distribNodes, + MCAuto& _coords, MCAuto& _part_coords, MCAuto& _fam_coords, MCAuto& _num_coords, MCAuto& _name_coords); static void LoadPartCoords(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it, mcIdType nMin, mcIdType nMax, -MCAuto& _coords, MCAuto& _part_coords, MCAuto& _fam_coords, MCAuto& _num_coords, MCAuto& _name_coords); + MCAuto& _coords, MCAuto& _part_coords, MCAuto& _fam_coords, MCAuto& _num_coords, MCAuto& _name_coords); static void LoadPartCoordsArray(med_idt fid, const std::vector& infosOnComp, const std::string& mName, int dt, int it, const DataArrayIdType *nodeIds, MCAuto& _coords, MCAuto& _fam_coords, MCAuto& _num_coords, MCAuto& _name_coords); + static void allocCoordsPartCoords(mcIdType spaceDim, mcIdType nMin, mcIdType nMax, MCAuto& _coords, MCAuto& _part_coords); + static void allocCoordsPartCoords(mcIdType spaceDim, const std::vector& nodeIds, MCAuto& _coords, MCAuto& _part_coords); + static void fillPartCoords(med_idt fid, mcIdType spaceDim, const std::string& mName, int dt, int it, const PartDefinition *partCoords, MCAuto& _coords, MCAuto& _fam_coords, MCAuto& _num_coords, MCAuto& _name_coords); private: void sortTypes(); private: diff --git a/src/MEDLoader/MEDFilterEntity.hxx b/src/MEDLoader/MEDFilterEntity.hxx new file mode 100644 index 000000000..265369361 --- /dev/null +++ b/src/MEDLoader/MEDFilterEntity.hxx @@ -0,0 +1,119 @@ +// Copyright (C) 2007-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anida Khizar (CEA/DES) + +#ifndef __MEDFILTERENTITY_HXX__ +#define __MEDFILTERENTITY_HXX__ + +#include "MEDCouplingPartDefinition.hxx" +#include "med.h" +#include + +#ifdef __GNUC__ +# include +#endif // __GNUC__ + +namespace MEDCoupling +{ + + /*! + * + * This class encapsulates the med_filter object to create the appropriate filter based on the partition given as input: + * if the partition represents a slice of values, then it's more efficient to have a block filter (to treat a block of data) + * otherwise, a generic filter is necessary + * + */ + class MEDFilterEntity + { + public: + inline MEDFilterEntity(); + ~MEDFilterEntity() { if (_filter != nullptr) MEDfilterClose(_filter.get()); } + + inline void fill(med_idt fid, mcIdType nbOfEntity, mcIdType nbOfValuesPerEntity, mcIdType nbOfConstituentPerValue, + const med_int constituentSelect, const med_switch_mode switchMode, const med_storage_mode storageMode, const char * const profileName, + const PartDefinition* pd); + const med_filter *getPtr() const { return _filter.get(); } + + private: + std::shared_ptr _filter; + }; + + MEDFilterEntity::MEDFilterEntity() : _filter(std::make_shared()) + { + med_filter& ref = *_filter.get(); + + // gcc < 9.x compilers are not able to assign to the shared_ptr th med_filter structure +#if defined(WIN32) + ref = MED_FILTER_INIT; +#else + #if defined(__GNUC__) && __GNUC_PREREQ(9,0) + ref = MED_FILTER_INIT; + #else + ref = (med_filter)MED_FILTER_INIT; + #endif +#endif // WIN32 + } + + void MEDFilterEntity::fill(med_idt fid, mcIdType nbOfEntity, mcIdType nbOfValuesPerEntity, mcIdType nbOfConstituentPerValue, + const med_int constituentSelect, const med_switch_mode switchMode, const med_storage_mode storageMode, const char * const profileName, + const PartDefinition* pd) + { + const SlicePartDefinition *spd(dynamic_cast(pd)); + if(spd) + { + //Here, pd contains a slice, so it's more efficient to define a filter of block + //(which will load contiguous values) + mcIdType nbOfEltsToLoad = spd->getNumberOfElems(); + mcIdType strt,end,step; + spd->getSlice(strt,end,step); + if(strt<0) + throw INTERP_KERNEL::Exception("MEDFilterEntity::fill : start pos is negative !"); + if(end>nbOfEntity) + throw INTERP_KERNEL::Exception("MEDFilterEntity::fill : end is after the authorized range !"); + MEDfilterBlockOfEntityCr(fid,ToMedInt(nbOfEntity),ToMedInt(nbOfValuesPerEntity),ToMedInt(nbOfConstituentPerValue), + constituentSelect,switchMode,storageMode,profileName, + /*start*/ToMedInt(strt+1),/*stride*/ToMedInt(step),/*count*/1,/*blocksize*/ToMedInt(nbOfEltsToLoad), + /*lastblocksize=useless because count=1*/0,_filter.get()); + return; + } + const DataArrayPartDefinition *dpd(dynamic_cast(pd)); + if(dpd) + { + mcIdType nbOfEltsToLoad = dpd->getNumberOfElems(); + + //convert to fortran indexing + std::vector dpdPlus1; + MCAuto partition(pd->toDAI()); + std::copy(partition->begin(), partition->end(), std::back_inserter(dpdPlus1)); + std::for_each(dpdPlus1.begin(), dpdPlus1.end(), [](mcIdType &node){ node+=1; }); + + //Here, pd contains a random selection of non-contiguous values: + //we need to use a more generic filter (less efficient) + MEDfilterEntityCr(fid,ToMedInt(nbOfEntity),ToMedInt(nbOfValuesPerEntity),ToMedInt(nbOfConstituentPerValue), + constituentSelect,switchMode,storageMode,profileName, + ToMedInt(nbOfEltsToLoad), dpdPlus1.data(), + _filter.get()); + return; + } + throw INTERP_KERNEL::Exception("MEDFilterEntity::fill : empty part definition !"); + } + +} // namespace + +#endif diff --git a/src/ParaMEDLoader/ParaMEDFileMesh.cxx b/src/ParaMEDLoader/ParaMEDFileMesh.cxx index c5b64689d..21f1b7d44 100644 --- a/src/ParaMEDLoader/ParaMEDFileMesh.cxx +++ b/src/ParaMEDLoader/ParaMEDFileMesh.cxx @@ -23,9 +23,48 @@ #include "MEDFileMesh.hxx" #include "MEDFileMeshLL.hxx" #include "MEDLoader.hxx" +#include "MEDFileField1TS.hxx" +#include "MEDFileUtilities.hxx" +#include "MEDFileEntities.hxx" +#include +#include + + +// From MEDLOader.cxx TU +extern med_geometry_type typmai3[INTERP_KERNEL::NORM_MAXTYPE]; using namespace MEDCoupling; +void getSingleGeometricType(const std::string& fileName, const std::string& mName, INTERP_KERNEL::NormalizedCellType& geoType) +{ + int meshDim, spaceDim; + mcIdType numberOfNodes; + std::vector< std::vector< std::pair > > typesDistrib(GetUMeshGlobalInfo(fileName,mName,meshDim,spaceDim,numberOfNodes)); + std::size_t numberOfTypesMaxDimension = typesDistrib[0].size(); + if(numberOfTypesMaxDimension != 1) + throw INTERP_KERNEL::Exception("ParaMEDFileMesh : only mesh with single geometrical type are supported with given distribution !"); + geoType = typesDistrib[0][0].first; +} + +void checkDistribution(const MPI_Comm& com, mcIdType totalNumberOfElements, const std::vector& distrib) +{ + mcIdType nbEltsInDistribLoc = distrib.size(); + mcIdType nbEltsInDistribTot = -1; +#ifdef HAVE_MPI + MPI_Allreduce(&nbEltsInDistribLoc, &nbEltsInDistribTot, 1, MPI_LONG, MPI_SUM, com); +#else + throw INTERP_KERNEL::Exception("not(HAVE_MPI) incompatible with MPI_World_Size>1"); +#endif + if(nbEltsInDistribTot != totalNumberOfElements) + { + if(nbEltsInDistribTot > totalNumberOfElements) + throw INTERP_KERNEL::Exception("ParaMEDFileMesh : Some of your partitions overlap each other ! Each element in your distribution vector must appear only once ! "); + else + throw INTERP_KERNEL::Exception("ParaMEDFileMesh : The distribution does not cover the whole mesh ! Each element of the mesh must appear once in your distribution vector "); + } +} + + MEDFileMesh *ParaMEDFileMesh::New(int iPart, int nbOfParts, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs) { MEDFileUtilities::CheckFileForRead(fileName); @@ -73,18 +112,90 @@ MEDFileUMesh *ParaMEDFileUMesh::New(int iPart, int nbOfParts, const std::string& return ParaMEDFileUMesh::NewPrivate(fid,iPart,nbOfParts,fileName,mName,dt,it,mrs); } -// MPI_COMM_WORLD, MPI_INFO_NULL -MEDFileUMesh *ParaMEDFileUMesh::ParaNew(int iPart, int nbOfParts, const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs) +/*! + * Opens the given file in parallel so that each processor can load a specific part of the mesh \a mName. + * Each processor will load the cells contained in the vector \a distrib (only nodes lying on those cells will be loaded), + * in order to read the entire mesh in parallel (memory consumption is thus distributed among all the processes). + * \param [in] distrib - map defining for each geometric type, the corresponding vector of cells we want to load with c-type indexing (starting from zero). + * Each vector in this map has an independant numerotation, which means on one processor, vectors of different types may contain the same numbers, they will not refer to the same cells + * (the i-th cell of a type A does not correspond to the i-th cell of type B) + * However they have to differ from one processor to another, as to ensure that: + * 1) each processor only loads a unique part of the mesh + * 2) the combined distribution vectors cover the entire mesh + * \param [in] com - group of MPI processes that will read the file + * \param [in] nfo- MPI info object (used to manage MPI routines) + * \param [in] filename - name of the file we want to read + * \param [in] mName - name of the mesh we want to read + * \param [in] dt - order at which to read the mesh + * \param [in] it - iteration at which to read the mesh + * \param [in] mrs - object used to read additional low-level information + * \return MEDFileUMesh* - a new instance of MEDFileUMesh. The + * caller is to delete this mesh using decrRef() as it is no more needed. + * \throw exception if the mesh contains multiple types of cells + * \throw exception if the partition of the mesh cells defined by \a distrib does not cover the whole mesh + */ +MEDFileUMesh *ParaMEDFileUMesh::ParaNew(const std::map> &distrib, const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs) { MEDFileUtilities::CheckFileForRead(fileName); #ifdef HDF5_IS_PARALLEL MEDFileUtilities::AutoFid fid(MEDparFileOpen(fileName.c_str(),MED_ACC_RDONLY,com,nfo)); #else MEDFileUtilities::AutoFid fid(MEDfileOpen(fileName.c_str(),MED_ACC_RDONLY)); +#endif + return ParaMEDFileUMesh::NewPrivate(fid,com,distrib,fileName,mName,dt,it,mrs); +} + + +/*! + * Opens the given file in parallel so that each processor can load its part of the mesh \a mName. + * The mesh will be equally and linearly distributed among all processes: + * the list of cells will be divided into \a nbOfParts slices and only slice \a iPart (cells and nodes lying on those cells) will be loaded by the current processor. + * The entire mesh is thus read in parallel and memory consumption is divided among the group of processes. + * \param [in] iPart - part of the mesh that will be loaded + * \param [in] nbOfParts - total number of parts in which to divide the mesh + * \param [in] com - group of MPI processes that will read the file + * \param [in] nfo- MPI info object (used to manage MPI routines) + * \param [in] filename - name of the file we want to read + * \param [in] mName - name of the mesh we want to read + * \param [in] dt - Time order at which to read the mesh + * \param [in] it - Time iteration at which to read the mesh + * \param [in] mrs - object used to read additional low-level information + * \return MEDFileUMesh* - a new instance of MEDFileUMesh. The + * caller is to delete this mesh using decrRef() as it is no more needed. + */ +MEDFileUMesh *ParaMEDFileUMesh::ParaNew(int iPart, int nbOfParts, const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs) +{ + MEDFileUtilities::CheckFileForRead(fileName); +#ifdef HDF5_IS_PARALLEL + MEDFileUtilities::AutoFid fid(MEDparFileOpen(fileName.c_str(),MED_ACC_RDONLY,com,nfo)); // MPI_COMM_WORLD, MPI_INFO_NULL +#else + MEDFileUtilities::AutoFid fid(MEDfileOpen(fileName.c_str(),MED_ACC_RDONLY)); #endif return ParaMEDFileUMesh::NewPrivate(fid,iPart,nbOfParts,fileName,mName,dt,it,mrs); } +/*! + * Loads mesh \a mName in parallel using a custom partition of the mesh cells among the processes. + * See ParaMEDFileUMesh::ParaNew for detailed description. + */ +MEDFileUMesh *ParaMEDFileUMesh::NewPrivate(med_idt fid, const MPI_Comm& com, const std::map>& distrib, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs) +{ + MCAuto ret; + for(std::map>::const_iterator iter=distrib.begin(); iter!= distrib.end(); iter++) + { + med_geometry_type geoMedType(typmai3[iter->first /*current geometric type*/]); + med_bool changement,transformation; + med_int totalNumberOfElements(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_CELL,geoMedType,MED_CONNECTIVITY,MED_NODAL,&changement,&transformation)); + checkDistribution(com,totalNumberOfElements,iter->second /*distrib over this geometric type*/); + } + ret=MEDFileUMesh::LoadPartOfFromUserDistrib(fid,mName,distrib,dt,it,mrs); + return ret.retn(); +} + +/*! + * Loads mesh \a mName in parallel using a slice partition of the mesh cells among the processes + * See ParaMEDFileUMesh::ParaNew for detailed description. + */ MEDFileUMesh *ParaMEDFileUMesh::NewPrivate(med_idt fid, int iPart, int nbOfParts, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs) { MCAuto ret; @@ -106,6 +217,62 @@ MEDFileUMesh *ParaMEDFileUMesh::NewPrivate(med_idt fid, int iPart, int nbOfParts return ret.retn(); } +/*! + * Loads field \a fName laying on mesh \a mName from the filename \a fileName in parallel: + * each processor will load their portion of the field (ie the portion laying on the cells in the vector \a distrib given in the parameters). + * WARNING : this will only load the array of values of the field, additionnal information of the local field such as the number of its tuples might be incorrect + * \param [in] com - group of MPI processes that will read the file + * \param [in] nfo- MPI info object (used to manage MPI routines) + * \param [in] fileName - name of the file containing the field + * \param [in] fName - name of the field we want to load + * \param [in] mName - name of the mesh on which the field is defined + * \param [in] distrib - vector of cells on which we want to load the field \a fName (with c-type indexing, so starting from zero). + * \param [in] dt - Time order at which to read the field + * \param [in] it - Time iteration at which to read the field + * \return MEDFileField1TS* - a new instance of MEDFileField1TS. The + * caller is to delete it using decrRef() as it is no more needed. + * \throw exception if the field is not of type FLOAT64 + * \throw exception if the mesh contains more than one geometric type + * \throw exception if the given distribution does not cover the entire mesh on which the field is defined + */ +MEDFileField1TS *ParaMEDFileField1TS::ParaNew(const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName, const std::string& fName, const std::string& mName, const std::vector& distrib, TypeOfField loc, int dt, int it) +{ + MEDFileUtilities::CheckFileForRead(fileName); +#ifdef HDF5_IS_PARALLEL + MEDFileUtilities::AutoFid fid(MEDparFileOpen(fileName.c_str(),MED_ACC_RDONLY,com,nfo)); +#else + MEDFileUtilities::AutoFid fid(MEDfileOpen(fileName.c_str(),MED_ACC_RDONLY)); +#endif + return ParaMEDFileField1TS::NewPrivate(fid,com,fName,mName,distrib,loc,dt,it); +} + +/*! + * Loads field \a fName in parallel using a custom partition of the mesh cells on which the field is defined among the processes. + * See ParaMEDFileField1TS::ParaNew for detailed description. + */ +MEDFileField1TS *ParaMEDFileField1TS::NewPrivate(med_idt fid, const MPI_Comm& com, const std::string& fName, const std::string& mName, const std::vector& distrib, TypeOfField loc, int dt, int it) +{ + INTERP_KERNEL::NormalizedCellType geoType; + getSingleGeometricType(MEDFileWritable::FileNameFromFID(fid),mName,geoType); + if(loc==ON_CELLS) //if distribution is on nodes, no fast way to check it (as a node can be shared by multiple processors) + { + med_geometry_type geoMedType(typmai3[geoType]); + med_bool changement,transformation; + med_int totalNumberOfElements(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_CELL,geoMedType,MED_FAMILY_NUMBER,MED_NODAL,&changement,&transformation)); + checkDistribution(com,totalNumberOfElements,distrib); + } + std::vector> tmp={ {loc, geoType} }; + INTERP_KERNEL::AutoCppPtr entities(MEDFileEntities::BuildFrom(&tmp)); + MCAuto partFile(MEDFileAnyTypeField1TS::NewAdv(fid,fName,dt,it,entities,distrib)); + + MCAuto ret(MEDCoupling::DynamicCast(partFile)); + if(ret.isNotNull()) + return ret.retn(); + else + throw INTERP_KERNEL::Exception("ParaMEDFileField1TS::ParaNew : only FLOAT64 field supported for the moment !"); +} + + MEDFileMeshes *ParaMEDFileMeshes::New(int iPart, int nbOfParts, const std::string& fileName) { std::vector ms(GetMeshNames(fileName)); diff --git a/src/ParaMEDLoader/ParaMEDFileMesh.hxx b/src/ParaMEDLoader/ParaMEDFileMesh.hxx index da482e306..18a3dc861 100644 --- a/src/ParaMEDLoader/ParaMEDFileMesh.hxx +++ b/src/ParaMEDLoader/ParaMEDFileMesh.hxx @@ -26,6 +26,11 @@ #include "mpi.h" #include +#include +#include +#include "MCIdType.hxx" +#include "MEDCouplingRefCountObject.hxx" +#include "NormalizedGeometricTypes" namespace MEDCoupling { @@ -33,6 +38,7 @@ namespace MEDCoupling class MEDFileUMesh; class MEDFileMeshes; class MEDFileMeshReadSelector; + class MEDFileField1TS; class ParaMEDFileMesh { @@ -46,16 +52,30 @@ namespace MEDCoupling public: static MEDFileUMesh *New(int iPart, int nbOfParts, const std::string& fileName, const std::string& mName, int dt=-1, int it=-1, MEDFileMeshReadSelector *mrs=0); static MEDFileUMesh *ParaNew(int iPart, int nbOfParts, const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName, const std::string& mName, int dt=-1, int it=-1, MEDFileMeshReadSelector *mrs=0); + static MEDFileUMesh *ParaNew(const std::map>&, const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName, const std::string& mName, int dt=-1, int it=-1, MEDFileMeshReadSelector *mrs=0); + private: static MEDFileUMesh *NewPrivate(med_idt fid, int iPart, int nbOfParts, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs); + static MEDFileUMesh *NewPrivate(med_idt fid, const MPI_Comm& com, const std::map>&, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs); }; + class ParaMEDFileMeshes { public: static MEDFileMeshes *New(int iPart, int nbOfParts, const std::string& fileName); static MEDFileMeshes *ParaNew(int iPart, int nbOfParts, const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName); }; + + class ParaMEDFileField1TS + { + public: + static MEDFileField1TS *ParaNew(const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName, const std::string& fName, const std::string& mName, const std::vector& distrib, TypeOfField loc, int dt=-1, int it=-1); + private: + static MEDFileField1TS *NewPrivate(med_idt fid, const MPI_Comm& com, const std::string& fName, const std::string& mName, const std::vector& distrib, TypeOfField loc, int dt, int it); + + }; + } #endif diff --git a/src/ParaMEDMEMTest/CMakeLists.txt b/src/ParaMEDMEMTest/CMakeLists.txt index b6813e2a5..83c1b7648 100644 --- a/src/ParaMEDMEMTest/CMakeLists.txt +++ b/src/ParaMEDMEMTest/CMakeLists.txt @@ -23,6 +23,7 @@ ADD_DEFINITIONS(${MPI_DEFINITIONS} ${CPPUNIT_DEFINITIONS}) INCLUDE_DIRECTORIES( ${MPI_INCLUDE_DIRS} + ${MEDFILE_INCLUDE_DIRS} ${CPPUNIT_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/../ParaMEDLoader ${CMAKE_CURRENT_SOURCE_DIR}/../ParaMEDMEM @@ -46,6 +47,7 @@ SET(ParaMEDMEMTest_SOURCES ParaMEDMEMTest_FabienAPI.cxx ParaMEDMEMTest_NonCoincidentDEC.cxx ParaMEDMEMTest_OverlapDEC.cxx + ParaMEDMEMTest_MEDLoader.cxx ) ADD_LIBRARY(ParaMEDMEMTest ${ParaMEDMEMTest_SOURCES}) diff --git a/src/ParaMEDMEMTest/ParaMEDMEMTest.hxx b/src/ParaMEDMEMTest/ParaMEDMEMTest.hxx index 240f94830..3223aaf48 100644 --- a/src/ParaMEDMEMTest/ParaMEDMEMTest.hxx +++ b/src/ParaMEDMEMTest/ParaMEDMEMTest.hxx @@ -85,6 +85,11 @@ class ParaMEDMEMTest : public CppUnit::TestFixture CPPUNIT_TEST(testFabienAPI1); // 3 procs CPPUNIT_TEST(testFabienAPI2); // 3 procs + CPPUNIT_TEST(testParallelLoad1); // 2 procs + CPPUNIT_TEST(testParallelLoad2); // 3 procs + CPPUNIT_TEST(testParallelLoad3); // 2 procs + CPPUNIT_TEST(testParallelLoad4); // 2 procs + CPPUNIT_TEST(testParallelLoad5); // 2 procs CPPUNIT_TEST_SUITE_END(); public: @@ -148,6 +153,12 @@ public: void testFabienAPI1(); void testFabienAPI2(); + void testParallelLoad1(); + void testParallelLoad2(); + void testParallelLoad3(); + void testParallelLoad4(); + void testParallelLoad5(); + std::string getTmpDirectory(); std::string makeTmpFile( const std::string&, const std::string& = "" ); @@ -166,6 +177,8 @@ private: void testInterpKernelDEC2_2D_(const char *srcMeth, const char *targetMeth); void testInterpKernelDEC_3D_(const char *srcMeth, const char *targetMeth); void testGauthier3_GEN(bool, int); + + }; // to automatically remove temporary files from disk diff --git a/src/ParaMEDMEMTest/ParaMEDMEMTest_MEDLoader.cxx b/src/ParaMEDMEMTest/ParaMEDMEMTest_MEDLoader.cxx index 485186b09..38deb0b3c 100644 --- a/src/ParaMEDMEMTest/ParaMEDMEMTest_MEDLoader.cxx +++ b/src/ParaMEDMEMTest/ParaMEDMEMTest_MEDLoader.cxx @@ -19,7 +19,11 @@ #include "ParaMEDMEMTest.hxx" #include "MEDLoader.hxx" -#include "MEDCouplingUMesh.hxx" + +#include "ParaMEDFileMesh.hxx" +#include "MEDFileMesh.hxx" +#include "MEDFileField1TS.hxx" +#include "TestInterpKernelUtils.hxx" #include "MEDCouplingFieldDouble.hxx" #include @@ -29,7 +33,351 @@ #include #include -using namespace std; -using namespace INTERP_KERNEL; using namespace MEDCoupling; +/* + * Generate a 2D mesh that is supposed to match the part that will be loaded by each proc in testParallelLoad1 + */ +MEDCouplingUMesh* genLocMesh2D(int rk) +{ + int nxTot=4,nyTot=2; + int nx=2,ny=2; + MCAuto msh = MEDCouplingCMesh::New("mesh"); + MCAuto dax = DataArrayDouble::New(); dax->alloc(nx+1,1); + MCAuto day = DataArrayDouble::New(); day->alloc(ny+1,1); + dax->iota(); day->iota(); + if (rk == 0) + { + std::transform(dax->begin(), dax->end(), + dax->rwBegin(), + [nxTot](const int& c){return c/(float)nxTot;}); + std::transform(day->begin(), day->end(), + day->rwBegin(), + [nyTot](const int& c){return c/(float)nyTot;}); + } + else + { + std::transform(dax->begin(), dax->end(), + dax->rwBegin(), + [nxTot](const int& c){return c/(float)nxTot+0.5; }); + std::transform(day->begin(), day->end(), + day->rwBegin(), + [nyTot](const int& c){return c/(float)nyTot;}); + } + msh->setCoords(dax, day); + MCAuto ret = msh->buildUnstructured(); + return ret.retn(); +} + +/* + * Generate a 2D mesh that is supposed to match the part that will be loaded by proc0 in testParallelLoad2 + */ +MEDCouplingUMesh* genLocMeshMultipleTypes1() +{ + MCAuto ret= MEDCouplingUMesh::New("mesh",2); + double coords[10] = {0.,1., 0.,2., 1.,2., 0.,3., 1.,3.}; + DataArrayDouble *myCoords=DataArrayDouble::New(); + myCoords->alloc(5,2); + std::copy(coords,coords+10,myCoords->getPointer()); + ret->setCoords(myCoords); + myCoords->decrRef(); + mcIdType conn[7]={0,2,1, 1,2,4,3}; + ret->allocateCells(2); + ret->insertNextCell(INTERP_KERNEL::NORM_TRI3,3,conn); + ret->insertNextCell(INTERP_KERNEL::NORM_QUAD4,4,conn+3); + ret->finishInsertingCells(); + return ret.retn(); +} + +/* + * Generate a 2D mesh that is supposed to match the part that will be loaded by proc1 in testParallelLoad2 + */ +MEDCouplingUMesh* genLocMeshMultipleTypes2() +{ + MCAuto ret= MEDCouplingUMesh::New("mesh",2); + double coords[10] = {0.,0., 1.,0., 0.,1., 1.,1., 1.,2.}; + DataArrayDouble *myCoords=DataArrayDouble::New(); + myCoords->alloc(5,2); + std::copy(coords,coords+10,myCoords->getPointer()); + ret->setCoords(myCoords); + myCoords->decrRef(); + mcIdType conn[7]={2,3,4, 0,1,3,2}; + ret->allocateCells(2); + ret->insertNextCell(INTERP_KERNEL::NORM_TRI3,3,conn); + ret->insertNextCell(INTERP_KERNEL::NORM_QUAD4,4,conn+3); + ret->finishInsertingCells(); + return ret.retn(); +} + +/* + * Generate a 2D mesh that is supposed to match the part that will be loaded by proc2 in testParallelLoad2 + */ +MEDCouplingUMesh* genLocMeshMultipleTypes3() +{ + MCAuto ret= MEDCouplingUMesh::New("mesh",2); + double coords[16] = {1.,0., 2.,0., 1.,1., 2.,1., 1.,2., 2.,2., 1.,3., 2.,3.}; + DataArrayDouble *myCoords=DataArrayDouble::New(); + myCoords->alloc(8,2); + std::copy(coords,coords+16,myCoords->getPointer()); + ret->setCoords(myCoords); + myCoords->decrRef(); + mcIdType conn[14]={0,1,3, 0,3,2, 2,3,5,4, 4,5,7,6}; + ret->allocateCells(4); + ret->insertNextCell(INTERP_KERNEL::NORM_TRI3,3,conn); + ret->insertNextCell(INTERP_KERNEL::NORM_TRI3,3,conn+3); + ret->insertNextCell(INTERP_KERNEL::NORM_QUAD4,4,conn+6); + ret->insertNextCell(INTERP_KERNEL::NORM_QUAD4,4,conn+10); + ret->finishInsertingCells(); + return ret.retn(); +} + +/* + * Generate a 2D field that is supposed to match the local field loaded by each proc in testParallelLoad4 + */ +MEDCouplingFieldDouble *genLocFieldCells(int rank) +{ + MCAuto mesh = genLocMesh2D(rank); + MCAuto f1=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + f1->setName("field"); + f1->setMesh(mesh); + + MCAuto array(DataArrayDouble::New()); + array->alloc(4,2); + std::vector values; + if(rank == 0) + values = { 0., 10., 20., 30., 80., 90., 100., 110.}; + else + values = { 40., 50., 60., 70., 120., 130., 140., 150.}; + std::copy(values.data(),values.data()+8,array->getPointer()); + array->setInfoOnComponent(0,""); + f1->setArray(array); + return f1.retn(); +} + +/* + * Generate a 2D field that is supposed to match the local field loaded by each proc in testParallelLoad5 + */ +MEDCouplingFieldDouble *genLocFieldNodes(int rank) +{ + MCAuto mesh = genLocMesh2D(rank); + MCAuto f1=MEDCouplingFieldDouble::New(ON_NODES,ONE_TIME); + f1->setName("field"); + f1->setMesh(mesh); + + MCAuto array(DataArrayDouble::New()); + array->alloc(9,2); + std::vector values; + if(rank == 0) + values= { 0., 10., 20., 30., 40., 50., 100., 110., 120., 130., 140., 150., 200., 210., 220., 230., 240., 250. }; + else + values= { 40., 50., 60., 70., 80., 90., 140., 150., 160., 170., 180., 190., 240., 250., 260., 270., 280., 290. }; + std::copy(values.data(),values.data()+18,array->getPointer()); + array->setInfoOnComponent(0,""); + f1->setArray(array); + return f1.retn(); +} + +/*! + * Test case to load a simple 2D cartesian mesh in parallel on 2 procs + */ +void ParaMEDMEMTest::testParallelLoad1() +{ + int size; + int rank; + MPI_Comm_size(MPI_COMM_WORLD,&size); + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + // + if(size!=2) + return ; + + std::map> distrib; + if (rank == 0) + distrib = { {INTERP_KERNEL::NORM_QUAD4,{0,1,4,5}/*c++ type of indexing: index starts from zero!*/} }; + else + distrib = { {INTERP_KERNEL::NORM_QUAD4,{2,3,6,7}} }; + + std::string filename=INTERP_TEST::getResourceFile("SimpleTest2D.med"); + MCAuto mu = ParaMEDFileUMesh::ParaNew(distrib, MPI_COMM_WORLD, MPI_INFO_NULL, filename, "mesh"); + MCAuto mesh = mu->getMeshAtLevel(0); + MCAuto meshRef = genLocMesh2D(rank); + CPPUNIT_ASSERT(mesh->isEqual(meshRef,1e-12)); + MPI_Barrier(MPI_COMM_WORLD); +} + +/*! + * Test case to load a 2D mesh made of squares and triangles in parallel on 3 procs. + * Each proc is going to load a part of the mesh. + */ +void ParaMEDMEMTest::testParallelLoad2() +{ + int size; + int rank; + MPI_Comm_size(MPI_COMM_WORLD,&size); + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + // + if(size!=3) + return ; + + std::map> distrib; + // independant numerotation for each geometric type! + if (rank == 0) + distrib = { {INTERP_KERNEL::NORM_TRI3,{3}} , {INTERP_KERNEL::NORM_QUAD4,{2}} }; + else if(rank == 1) + distrib = { {INTERP_KERNEL::NORM_TRI3,{2}} , {INTERP_KERNEL::NORM_QUAD4,{0}} }; + else + distrib= { {INTERP_KERNEL::NORM_TRI3,{0,1}} , {INTERP_KERNEL::NORM_QUAD4,{1,3}} }; + + std::string filename=INTERP_TEST::getResourceFile("Test2DMultiGeoType.med"); + MCAuto mu = ParaMEDFileUMesh::ParaNew(distrib, MPI_COMM_WORLD, MPI_INFO_NULL, filename, "mesh"); + MCAuto mesh = mu->getMeshAtLevel(0); + MEDCouplingUMesh *meshRef; + if(rank==0) + meshRef=genLocMeshMultipleTypes1(); + else if(rank==1) + meshRef=genLocMeshMultipleTypes2(); + else + meshRef=genLocMeshMultipleTypes3(); + //checking that all 3 procs have correctly loaded their part + int equal = (int)mesh->isEqual(meshRef,1e-12); + int allEqual = -1; + MPI_Allreduce(&equal, &allEqual, 1, MPI_INT,MPI_SUM,MPI_COMM_WORLD); + CPPUNIT_ASSERT(allEqual==3); + + meshRef->decrRef(); + MPI_Barrier(MPI_COMM_WORLD); +} + +/*! + * Test case to load a 3D box meshed with tetras in parallel on 2 procs + */ +void ParaMEDMEMTest::testParallelLoad3() +{ + int size; + int rank; + MPI_Comm_size(MPI_COMM_WORLD,&size); + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + // + if(size!=2) + return ; + + std::map> distrib; + if (rank == 0) + { + std::vector distribCells = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,48,49,50,51,52,53,54,55,56,57, + 58,59,60,61,62,63,64,65,66,67,68,69,70,71,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118, + 119,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167}; + distrib = { {INTERP_KERNEL::NORM_TETRA4,distribCells} }; + } + else + { + std::vector distribCells = {24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,72,73,74,75,76,77,78,79,80, + 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142, + 143,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191}; + distrib = { {INTERP_KERNEL::NORM_TETRA4,distribCells} }; + } + + std::string filename=INTERP_TEST::getResourceFile("SimpleTest3D.med"); + MCAuto mu = ParaMEDFileUMesh::ParaNew(distrib, MPI_COMM_WORLD, MPI_INFO_NULL, filename, "mesh"); + MCAuto mesh = mu->getMeshAtLevel(0); + CPPUNIT_ASSERT_EQUAL(96,(int)mesh->getNumberOfCells()); + + // checking nodal connectivity + double nodalConnec[480] = {14, 1, 7, 18, 24, 14, 7, 6, 18, 24, 14, 6, 0, 18, 24, 14, 0, 1, 18, 24, 14, 1, 0, 19, 24, 14, 0, 2, 19, 24, 14, 2, 3, 19, 24, + 14, 3, 1, 19, 24, 14, 1, 3, 20, 24, 14, 3, 9, 20, 24, 14, 9, 7, 20, 24, 14, 7, 1, 20, 24, 14, 0, 6, 21, 24, 14, 6, 8, 21, 24, 14, 8, 2, 21, 24, + 14, 2, 0, 21, 24, 14, 7, 9, 22, 24, 14, 9, 8, 22, 24, 14, 8, 6, 22, 24, 14, 6, 7, 22, 24, 14, 2, 8, 23, 24, 14, 8, 9, 23, 24, 14, 9, 3, 23, 24, + 14, 3, 2, 23, 24, 14, 3, 9, 25, 31, 14, 9, 8, 25, 31, 14, 8, 2, 25, 31, 14, 2, 3, 25, 31, 14, 3, 2, 26, 31, 14, 2, 4, 26, 31, 14, 4, 5, 26, 31, + 14, 5, 3, 26, 31, 14, 3, 5, 27, 31, 14, 5, 11, 27, 31, 14, 11, 9, 27, 31, 14, 9, 3, 27, 31, 14, 2, 8, 28, 31, 14, 8, 10, 28, 31, 14, 10, 4, 28, 31, + 14, 4, 2, 28, 31, 14, 9, 11, 29, 31, 14, 11, 10, 29, 31, 14, 10, 8, 29, 31, 14, 8, 9, 29, 31, 14, 4, 10, 30, 31, 14, 10, 11, 30, 31, 14, 11, 5, 30, 31, + 14, 5, 4, 30, 31, 14, 7, 13, 32, 38, 14, 13, 12, 32, 38, 14, 12, 6, 32, 38, 14, 6, 7, 32, 38, 14, 7, 6, 33, 38, 14, 6, 8, 33, 38, 14, 8, 9, 33, 38, + 14, 9, 7, 33, 38, 14, 7, 9, 34, 38, 14, 9, 15, 34, 38, 14, 15, 13, 34, 38, 14, 13, 7, 34, 38, 14, 6, 12, 35, 38, 14, 12, 14, 35, 38, 14, 14, 8, 35, 38, + 14, 8, 6, 35, 38, 14, 13, 15, 36, 38, 14, 15, 14, 36, 38, 14, 14, 12, 36, 38, 14, 12, 13, 36, 38, 14, 8, 14, 37, 38, 14, 14, 15, 37, 38, 14, 15, 9, 37, 38, + 14, 9, 8, 37, 38, 14, 9, 15, 39, 45, 14, 15, 14, 39, 45, 14, 14, 8, 39, 45, 14, 8, 9, 39, 45, 14, 9, 8, 40, 45, 14, 8, 10, 40, 45, 14, 10, 11, 40, 45, + 14, 11, 9, 40, 45, 14, 9, 11, 41, 45, 14, 11, 17, 41, 45, 14, 17, 15, 41, 45, 14, 15, 9, 41, 45, 14, 8, 14, 42, 45, 14, 14, 16, 42, 45, 14, 16, 10, 42, 45, + 14, 10, 8, 42, 45, 14, 15, 17, 43, 45, 14, 17, 16, 43, 45, 14, 16, 14, 43, 45, 14, 14, 15, 43, 45, 14, 10, 16, 44, 45, 14, 16, 17, 44, 45, 14, 17, 11, 44, 45, + 14, 11, 10, 44, 45}; + const mcIdType *nc=mesh->getNodalConnectivity()->getConstPointer(); + CPPUNIT_ASSERT_EQUAL(480,(int)mesh->getNodalConnectivity()->getNumberOfTuples()); + CPPUNIT_ASSERT(std::equal(nodalConnec,nodalConnec+480,nc)); + + double nodalConnecInd[97] = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, + 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240, 245, 250, 255, 260, 265 ,270, 275, 280, 285, 290, 295, 300, 305, 310, 315, 320, + 325, 330, 335, 340, 345, 350, 355, 360, 365, 370, 375, 380, 385, 390, 395, 400, 405, 410, 415, 420, 425, 430, 435, 440, 445, 450, 455, 460, 465, 470, 475, 480}; + const mcIdType *ncIndx=mesh->getNodalConnectivityIndex()->getConstPointer(); + CPPUNIT_ASSERT_EQUAL(97,(int)mesh->getNodalConnectivityIndex()->getNumberOfTuples()); + CPPUNIT_ASSERT(std::equal(nodalConnecInd,nodalConnecInd+97,ncIndx)); + + // checking coords + std::vector coords(138); + if(rank == 0) + coords = {0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 2.0, 2.0, 0.0, 0.0, 4.0, 0.0, 2.0, 4.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0, 2.0, 0.0, 2.0, + 2.0, 2.0, 2.0, 2.0, 0.0, 4.0, 2.0, 2.0, 4.0, 2.0, 0.0, 0.0, 4.0, 2.0, 0.0, 4.0, 0.0, 2.0, 4.0, 2.0, 2.0, 4.0, 0.0, 4.0, 4.0, 2.0, 4.0, 4.0, 1.0, 0.0, + 1.0, 1.0, 1.0, 0.0, 2.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 3.0, 0.0, 2.0, 3.0, 1.0, 0.0, 3.0, + 1.0, 1.0, 3.0, 2.0, 1.0, 4.0, 1.0, 1.0, 3.0, 1.0, 1.0, 0.0, 3.0, 1.0, 1.0, 2.0, 2.0, 1.0, 3.0, 0.0, 1.0, 3.0, 1.0, 1.0, 4.0, 1.0, 2.0, 3.0, 1.0, 1.0, + 3.0, 1.0, 2.0, 3.0, 1.0, 3.0, 2.0, 2.0, 3.0, 3.0, 0.0, 3.0, 3.0, 1.0, 3.0, 4.0, 1.0, 4.0, 3.0, 1.0, 3.0, 3.0 }; + else + coords = {2.0, 0.0, 0.0, 4.0, 0.0, 0.0, 2.0, 2.0, 0.0, 4.0, 2.0, 0.0, 2.0, 4.0, 0.0, 4.0, 4.0, 0.0, 2.0, 0.0, 2.0, 4.0, 0.0, 2.0, 2.0, 2.0, 2.0, 4.0, + 2.0, 2.0, 2.0, 4.0, 2.0, 4.0, 4.0, 2.0, 2.0, 0.0, 4.0, 4.0, 0.0, 4.0, 2.0, 2.0, 4.0, 4.0, 2.0, 4.0, 2.0, 4.0, 4.0, 4.0, 4.0, 4.0, 3.0, 0.0, 1.0, 3.0, + 1.0, 0.0, 4.0, 1.0, 1.0, 2.0, 1.0, 1.0, 3.0, 1.0, 2.0, 3.0, 2.0, 1.0, 3.0, 1.0, 1.0, 3.0, 2.0, 1.0, 3.0, 3.0, 0.0, 4.0, 3.0, 1.0, 2.0, 3.0, 1.0, 3.0, + 3.0, 2.0, 3.0, 4.0, 1.0, 3.0, 3.0, 1.0, 3.0, 0.0, 3.0, 3.0, 1.0, 2.0, 4.0, 1.0, 3.0, 2.0, 1.0, 3.0, 3.0, 1.0, 4.0, 3.0, 2.0, 3.0, 3.0, 1.0, 3.0, 3.0, + 2.0, 3.0, 3.0, 3.0, 2.0, 4.0, 3.0, 3.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 3.0, 4.0, 3.0, 3.0, 3.0, 3.0 }; + const double *coo=mesh->getCoords()->getConstPointer(); + CPPUNIT_ASSERT_EQUAL(46,(int)mesh->getCoords()->getNumberOfTuples()); + CPPUNIT_ASSERT(std::equal(coords.data(),coords.data()+138,coo)); + + MPI_Barrier(MPI_COMM_WORLD); +} + +/*! + * Test case to load a field located on cells in parallel on 2 procs. + */ +void ParaMEDMEMTest::testParallelLoad4() +{ + int size; + int rank; + MPI_Comm_size(MPI_COMM_WORLD,&size); + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + // + if(size!=2) + return ; + + std::vector distrib; + if (rank == 0) + distrib = {0,1,4,5}; //c++ type of indexing: index starts from zero! + else + distrib = {2,3,6,7}; + + std::string filename=INTERP_TEST::getResourceFile("SimpleTest2D.med"); + MCAuto f1TS = ParaMEDFileField1TS::ParaNew(MPI_COMM_WORLD, MPI_INFO_NULL,filename,"fieldOnCells","mesh",distrib,ON_CELLS); + MCAuto fieldRef = genLocFieldCells(rank); + CPPUNIT_ASSERT(f1TS->getUndergroundDataArray()->isEqual(*fieldRef->getArray(),1e-12)); + MPI_Barrier(MPI_COMM_WORLD); +} + +/*! + * Test case to load a field located on nodes in parallel on 2 procs. + */ +void ParaMEDMEMTest::testParallelLoad5() +{ + int size; + int rank; + MPI_Comm_size(MPI_COMM_WORLD,&size); + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + // + if(size!=2) + return ; + + std::vector distrib; + if (rank == 0) + distrib = {0,1,2,5,6,7,10,11,12}; //c++ type of indexing: index starts from zero! + else + distrib = {2,3,4,7,8,9,12,13,14}; + + std::string filename=INTERP_TEST::getResourceFile("SimpleTest2D.med"); + MCAuto f1TS = ParaMEDFileField1TS::ParaNew(MPI_COMM_WORLD, MPI_INFO_NULL,filename,"fieldOnNodes","mesh",distrib,ON_NODES); + MCAuto fieldRef = genLocFieldNodes(rank); + CPPUNIT_ASSERT(f1TS->getUndergroundDataArray()->isEqual(*fieldRef->getArray(),1e-12)); + MPI_Barrier(MPI_COMM_WORLD); +} + + + -- 2.39.2