source: XIOS/dev/dev_ym/XIOS_SERVICES/src/node/context.cpp @ 1780

Last change on this file since 1780 was 1766, checked in by ymipsl, 5 years ago

more cleaning...
YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 76.8 KB
RevLine 
[219]1#include "context.hpp"
[352]2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
[219]5
6#include "calendar_type.hpp"
[278]7#include "duration.hpp"
[219]8
[300]9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "nc4_data_output.hpp"
[346]12#include "node_type.hpp"
[352]13#include "message.hpp"
14#include "type.hpp"
[591]15#include "xios_spl.hpp"
[1158]16#include "timer.hpp"
17#include "memtrack.hpp"
[1215]18#include <limits>
[1349]19#include <fstream>
[992]20#include "server.hpp"
[1349]21#include "distribute_file_server2.hpp"
[1761]22#include "services_manager.hpp"
23#include "contexts_manager.hpp"
24#include "cxios.hpp"
25#include "client.hpp"
[697]26
[335]27namespace xios {
[509]28
[1542]29  std::shared_ptr<CContextGroup> CContext::root;
[509]30
[219]31   /// ////////////////////// Définitions ////////////////////// ///
32
33   CContext::CContext(void)
34      : CObjectTemplate<CContext>(), CContextAttributes()
[983]35      , calendar(), hasClient(false), hasServer(false)
[1139]36      , isPostProcessed(false), finalized(false)
[1761]37      , idServer_(), client(nullptr), server(nullptr)
[1764]38      , allProcessed(false), countChildContextFinalized_(0), isProcessingEvent_(false)
[1622]39
[219]40   { /* Ne rien faire de plus */ }
41
42   CContext::CContext(const StdString & id)
43      : CObjectTemplate<CContext>(id), CContextAttributes()
[983]44      , calendar(), hasClient(false), hasServer(false)
[1139]45      , isPostProcessed(false), finalized(false)
[1761]46      , idServer_(), client(nullptr), server(nullptr)
[1764]47      , allProcessed(false), countChildContextFinalized_(0), isProcessingEvent_(false)
[219]48   { /* Ne rien faire de plus */ }
49
50   CContext::~CContext(void)
[509]51   {
[597]52     delete client;
53     delete server;
[1071]54     for (std::vector<CContextClient*>::iterator it = clientPrimServer.begin(); it != clientPrimServer.end(); it++)  delete *it;
55     for (std::vector<CContextServer*>::iterator it = serverPrimServer.begin(); it != serverPrimServer.end(); it++)  delete *it;
[1139]56
[300]57   }
[219]58
59   //----------------------------------------------------------------
[509]60   //! Get name of context
[219]61   StdString CContext::GetName(void)   { return (StdString("context")); }
62   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
63   ENodeType CContext::GetType(void)   { return (eContext); }
64
65   //----------------------------------------------------------------
[640]66
[509]67   /*!
68   \brief Get context group (context root)
69   \return Context root
70   */
[347]71   CContextGroup* CContext::getRoot(void)
[1622]72   TRY
[509]73   {
[1542]74      if (root.get()==NULL) root=std::shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
[509]75      return root.get();
[219]76   }
[1622]77   CATCH
[219]78
[640]79   //----------------------------------------------------------------
[509]80
81   /*!
82   \brief Get calendar of a context
83   \return Calendar
84   */
[1542]85   std::shared_ptr<CCalendar> CContext::getCalendar(void) const
[1622]86   TRY
[219]87   {
88      return (this->calendar);
89   }
[1622]90   CATCH
[509]91
[219]92   //----------------------------------------------------------------
[640]93
[509]94   /*!
95   \brief Set a context with a calendar
96   \param[in] newCalendar new calendar
97   */
[1542]98   void CContext::setCalendar(std::shared_ptr<CCalendar> newCalendar)
[1622]99   TRY
[219]100   {
101      this->calendar = newCalendar;
102   }
[1622]103   CATCH_DUMP_ATTR
[509]104
[219]105   //----------------------------------------------------------------
[509]106   /*!
107   \brief Parse xml file and write information into context object
108   \param [in] node xmld node corresponding in xml file
109   */
[219]110   void CContext::parse(xml::CXMLNode & node)
[1622]111   TRY
[219]112   {
113      CContext::SuperClass::parse(node);
114
115      // PARSING POUR GESTION DES ENFANTS
[278]116      xml::THashAttributes attributes = node.getAttributes();
[219]117
[278]118      if (attributes.end() != attributes.find("src"))
119      {
120         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
[462]121         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
122            ERROR("void CContext::parse(xml::CXMLNode & node)",
123                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
[278]124         if (!ifs.good())
125            ERROR("CContext::parse(xml::CXMLNode & node)",
126                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
[462]127         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
[278]128      }
129
[219]130      if (node.getElementName().compare(CContext::GetName()))
[421]131         DEBUG("Le noeud is wrong defined but will be considered as a context !");
[219]132
133      if (!(node.goToChildElement()))
134      {
135         DEBUG("Le context ne contient pas d'enfant !");
136      }
137      else
138      {
139         do { // Parcours des contextes pour traitement.
140
141            StdString name = node.getElementName();
142            attributes.clear();
143            attributes = node.getAttributes();
144
145            if (attributes.end() != attributes.find("id"))
[509]146            {
147              DEBUG(<< "Definition node has an id,"
148                    << "it will not be taking account !");
149            }
[219]150
151#define DECLARE_NODE(Name_, name_)    \
152   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
[549]153   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
[219]154#define DECLARE_NODE_PAR(Name_, name_)
155#include "node_type.conf"
[286]156
[421]157            DEBUG(<< "The element \'"     << name
158                  << "\' in the context \'" << CContext::getCurrent()->getId()
159                  << "\' is not a definition !");
[219]160
161         } while (node.goToNextElement());
162
163         node.goToParentElement(); // Retour au parent
164      }
165   }
[1622]166   CATCH_DUMP_ATTR
[219]167
168   //----------------------------------------------------------------
[509]169   //! Show tree structure of context
[219]170   void CContext::ShowTree(StdOStream & out)
[1622]171   TRY
[219]172   {
[549]173      StdString currentContextId = CContext::getCurrent() -> getId();
[347]174      std::vector<CContext*> def_vector =
[346]175         CContext::getRoot()->getChildList();
[347]176      std::vector<CContext*>::iterator
[219]177         it = def_vector.begin(), end = def_vector.end();
178
179      out << "<? xml version=\"1.0\" ?>" << std::endl;
180      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
[509]181
[219]182      for (; it != end; it++)
183      {
[509]184         CContext* context = *it;
185         CContext::setCurrent(context->getId());
[219]186         out << *context << std::endl;
187      }
[509]188
[219]189      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
[509]190      CContext::setCurrent(currentContextId);
[219]191   }
[1622]192   CATCH
[346]193
[219]194   //----------------------------------------------------------------
195
[509]196   //! Convert context object into string (to print)
[219]197   StdString CContext::toString(void) const
[1622]198   TRY
[219]199   {
200      StdOStringStream oss;
201      oss << "<" << CContext::GetName()
202          << " id=\"" << this->getId() << "\" "
203          << SuperClassAttribute::toString() << ">" << std::endl;
204      if (!this->hasChild())
205      {
206         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
207      }
208      else
209      {
210
211#define DECLARE_NODE(Name_, name_)    \
[346]212   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
213   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
[219]214#define DECLARE_NODE_PAR(Name_, name_)
215#include "node_type.conf"
216
217      }
218      oss << "</" << CContext::GetName() << " >";
219      return (oss.str());
220   }
[1622]221   CATCH
[219]222
223   //----------------------------------------------------------------
224
[509]225   /*!
226   \brief Find all inheritace among objects in a context.
227   \param [in] apply (true) write attributes of parent into ones of child if they are empty
228                     (false) write attributes of parent into a new container of child
229   \param [in] parent unused
230   */
[445]231   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
[1622]232   TRY
[219]233   {
234#define DECLARE_NODE(Name_, name_)    \
[354]235   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
[445]236     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
[219]237#define DECLARE_NODE_PAR(Name_, name_)
238#include "node_type.conf"
239   }
[1622]240   CATCH_DUMP_ATTR
[219]241
242   //----------------------------------------------------------------
243
[509]244   //! Verify if all root definition in the context have child.
[219]245   bool CContext::hasChild(void) const
[1622]246   TRY
[219]247   {
248      return (
249#define DECLARE_NODE(Name_, name_)    \
[346]250   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
[219]251#define DECLARE_NODE_PAR(Name_, name_)
252#include "node_type.conf"
253      false);
254}
[1622]255   CATCH
[219]256
257   //----------------------------------------------------------------
258
259   void CContext::CleanTree(void)
[1622]260   TRY
[219]261   {
[549]262#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
[219]263#define DECLARE_NODE_PAR(Name_, name_)
264#include "node_type.conf"
265   }
[1622]266   CATCH
267
[219]268   ///---------------------------------------------------------------
[509]269
[1761]270
[1765]271    /*!
[1330]272    Sets client buffers.
273    \param [in] contextClient
274    \param [in] bufferForWriting True if buffers are used for sending data for writing
275    This flag is only true for client and server-1 for communication with server-2
276  */
277   void CContext::setClientServerBuffer(CContextClient* contextClient, bool bufferForWriting)
[1622]278   TRY
[509]279   {
[1201]280      // Estimated minimum event size for small events (10 is an arbitrary constant just for safety)
[1372]281     const size_t minEventSize = CEventClient::headerSize + getIdServer().size() + 10 * sizeof(int);
[1201]282
283      // Ensure there is at least some room for 20 of such events in the buffers
284      size_t minBufferSize = std::max(CXios::minBufferSize, 20 * minEventSize);
285
[583]286#define DECLARE_NODE(Name_, name_)    \
[731]287     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
[583]288#define DECLARE_NODE_PAR(Name_, name_)
289#include "node_type.conf"
[719]290#undef DECLARE_NODE
291#undef DECLARE_NODE_PAR
292
[1201]293     // Compute the buffer sizes needed to send the attributes and data corresponding to fields
[917]294     std::map<int, StdSize> maxEventSize;
[1330]295     std::map<int, StdSize> bufferSize = getAttributesBufferSize(maxEventSize, contextClient, bufferForWriting);
296     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize, contextClient, bufferForWriting);
[729]297
[909]298     std::map<int, StdSize>::iterator it, ite = dataBufferSize.end();
[731]299     for (it = dataBufferSize.begin(); it != ite; ++it)
300       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
301
[1227]302     // Apply the buffer size factor, check that we are above the minimum buffer size and below the maximum size
[909]303     ite = bufferSize.end();
304     for (it = bufferSize.begin(); it != ite; ++it)
305     {
306       it->second *= CXios::bufferSizeFactor;
307       if (it->second < minBufferSize) it->second = minBufferSize;
[1227]308       if (it->second > CXios::maxBufferSize) it->second = CXios::maxBufferSize;
[909]309     }
310
[1201]311     // Leaders will have to send some control events so ensure there is some room for those in the buffers
[1184]312     if (contextClient->isServerLeader())
[598]313     {
[1184]314       const std::list<int>& ranks = contextClient->getRanksServerLeader();
[729]315       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
[1201]316       {
317         if (!bufferSize.count(*itRank))
318         {
319           bufferSize[*itRank] = minBufferSize;
320           maxEventSize[*itRank] = minEventSize;
321         }
322       }
[598]323     }
[1184]324     contextClient->setBufferSize(bufferSize, maxEventSize);
[509]325   }
[1622]326   CATCH_DUMP_ATTR
[509]327
328   //! Verify whether a context is initialized
[461]329   bool CContext::isInitialized(void)
[1622]330   TRY
[461]331   {
[549]332     return hasClient;
[461]333   }
[1622]334   CATCH_DUMP_ATTR
[509]335
[1761]336
337   void CContext::init(CServerContext* parentServerContext, MPI_Comm intraComm, int serviceType)
338   TRY
339   {
340     parentServerContext_ = parentServerContext ;
341     if (serviceType==CServicesManager::CLIENT) 
342       initClient(intraComm, serviceType) ;
343     else
344       initServer(intraComm, serviceType) ;
345    }
346    CATCH_DUMP_ATTR
347
348
349
350//! Initialize client side
351   void CContext::initClient(MPI_Comm intraComm, int serviceType)
352   TRY
353   {
354      intraComm_=intraComm ;
355      serviceType_ = CServicesManager::CLIENT ;
356      if (serviceType_==CServicesManager::CLIENT)
357      {
358        hasClient=true ;
359        hasServer=false ;
360      }
361      contextId_ = getId() ;
362     
363      attached_mode=true ;
364      if (!CXios::isUsingServer()) attached_mode=false ;
365
366
367      string contextRegistryId=getId() ;
368      registryIn=new CRegistry(intraComm);
369      registryIn->setPath(contextRegistryId) ;
370     
371      int commRank ;
372      MPI_Comm_rank(intraComm_,&commRank) ;
373      if (commRank==0) registryIn->fromFile("xios_registry.bin") ;
374      registryIn->bcastRegistry() ;
375      registryOut=new CRegistry(intraComm_) ;
376      registryOut->setPath(contextRegistryId) ;
377     
378   }
379   CATCH_DUMP_ATTR
380
381   
382   void CContext::initServer(MPI_Comm intraComm, int serviceType)
383   TRY
384   {
385     hasServer=true;
386     intraComm_=intraComm ;
387     serviceType_=serviceType ;
388
389     if (serviceType_==CServicesManager::GATHERER)
390     {
391       hasClient=true ;
392       hasServer=true ;
393     }
394     else if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::OUT_SERVER)
395     {
396       hasClient=false ;
397       hasServer=true ;
398     }
399
400     CXios::getContextsManager()->getContextId(getId(), contextId_, intraComm) ;
401     
402     registryIn=new CRegistry(intraComm);
403     registryIn->setPath(contextId_) ;
404     
405     int commRank ;
406     MPI_Comm_rank(intraComm_,&commRank) ;
407     if (commRank==0) registryIn->fromFile("xios_registry.bin") ;
408   
409     registryIn->bcastRegistry() ;
410     registryOut=new CRegistry(intraComm) ;
411     registryOut->setPath(contextId_) ;
412
413   }
414   CATCH_DUMP_ATTR
415
416
417  void CContext::createClientInterComm(MPI_Comm interCommClient, MPI_Comm interCommServer) // for servers
418  TRY
419  {
420    MPI_Comm intraCommClient ;
421    MPI_Comm_dup(intraComm_, &intraCommClient);
422    comms.push_back(intraCommClient);
[1764]423    // attached_mode=parentServerContext_->isAttachedMode() ; //ym probably inherited from source context
[1761]424    server = new CContextServer(this,intraComm_, interCommServer); // check if we need to dupl. intraComm_ ?
425    client = new CContextClient(this,intraCommClient,interCommClient);
426
427  }
428  CATCH_DUMP_ATTR
429
430  void CContext::createServerInterComm(void) 
431  TRY
432  {
433   
434    MPI_Comm interCommClient, interCommServer ;
435
436    if (serviceType_ == CServicesManager::CLIENT)
437    {
438
439      int commRank ;
440      MPI_Comm_rank(intraComm_,&commRank) ;
441      if (commRank==0)
442      {
443        if (attached_mode) CXios::getContextsManager()->createServerContext(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, getContextId()) ;
444        else if (CXios::usingServer2) CXios::getContextsManager()->createServerContext(CXios::defaultPoolId, CXios::defaultGathererId, 0, getContextId()) ;
445        else  CXios::getContextsManager()->createServerContext(CXios::defaultPoolId, CXios::defaultServerId, 0, getContextId()) ;
446      }
447
448      MPI_Comm interComm ;
449     
450      if (attached_mode)
451      {
452        parentServerContext_->createIntercomm(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, getContextId(), intraComm_, 
453                                              interCommClient, interCommServer) ;
454        int type ; 
455        if (commRank==0) CXios::getServicesManager()->getServiceType(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, type) ;
456        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
457        setIdServer(CXios::getContextsManager()->getServerContextName(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, type, getContextId())) ;
458        setCurrent(getId()) ; // getCurrent/setCurrent may be supress, it can cause a lot of trouble
459      }
460      else if (CXios::usingServer2)
461      { 
462//      CXios::getContextsManager()->createServerContextIntercomm(CXios::defaultPoolId, CXios::defaultGathererId, 0, getContextId(), intraComm_, interComm) ;
463        parentServerContext_->createIntercomm(CXios::defaultPoolId, CXios::defaultGathererId, 0, getContextId(), intraComm_,
464                                              interCommClient, interCommServer) ;
465        int type ; 
466        if (commRank==0) CXios::getServicesManager()->getServiceType(CXios::defaultPoolId, CXios::defaultGathererId, 0, type) ;
467        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
468        setIdServer(CXios::getContextsManager()->getServerContextName(CXios::defaultPoolId, CXios::defaultGathererId, 0, type, getContextId())) ;
469      }
470      else
471      {
472        //CXios::getContextsManager()->createServerContextIntercomm(CXios::defaultPoolId, CXios::defaultServerId, 0, getContextId(), intraComm_, interComm) ;
473        parentServerContext_->createIntercomm(CXios::defaultPoolId, CXios::defaultServerId, 0, getContextId(), intraComm_,
474                                              interCommClient, interCommServer) ;
475        int type ; 
476        if (commRank==0) CXios::getServicesManager()->getServiceType(CXios::defaultPoolId, CXios::defaultServerId, 0, type) ;
477        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
478        setIdServer(CXios::getContextsManager()->getServerContextName(CXios::defaultPoolId, CXios::defaultServerId, 0, type, getContextId())) ;
479      }
480
481        // intraComm client is not duplicated. In all the code we use client->intraComm for MPI
482        // in future better to replace it by intracommuncator associated to the context
[1765]483   
[1761]484      MPI_Comm intraCommClient, intraCommServer ;
485      intraCommClient=intraComm_ ;
486      MPI_Comm_dup(intraComm_, &intraCommServer) ;
487      client = new CContextClient(this, intraCommClient, interCommClient);
488      server = new CContextServer(this, intraCommServer, interCommServer);
489   
490    }
491   
492    if (serviceType_ == CServicesManager::GATHERER)
493    {
494      int commRank ;
495      MPI_Comm_rank(intraComm_,&commRank) ;
496     
497      int nbPartitions ;
498      if (commRank==0) 
499      { 
500        CXios::getServicesManager()->getServiceNbPartitions(CXios::defaultPoolId, CXios::defaultServerId, 0, nbPartitions) ;
501        for(int i=0 ; i<nbPartitions; i++)
502          CXios::getContextsManager()->createServerContext(CXios::defaultPoolId, CXios::defaultServerId, i, getContextId()) ;
503      }     
504      MPI_Bcast(&nbPartitions, 1, MPI_INT, 0, intraComm_) ;
505     
506      MPI_Comm interComm ;
507      for(int i=0 ; i<nbPartitions; i++)
508      {
509        parentServerContext_->createIntercomm(CXios::defaultPoolId, CXios::defaultServerId, i, getContextId(), intraComm_, interCommClient, interCommServer) ;
510        int type ; 
511        if (commRank==0) CXios::getServicesManager()->getServiceType(CXios::defaultPoolId, CXios::defaultServerId, 0, type) ;
512        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
513        primServerId_.push_back(CXios::getContextsManager()->getServerContextName(CXios::defaultPoolId, CXios::defaultServerId, i, type, getContextId())) ;
514
515        // intraComm client is not duplicated. In all the code we use client->intraComm for MPI
516        // in future better to replace it by intracommuncator associated to the context
517     
518        MPI_Comm intraCommClient, intraCommServer ;
519
520        intraCommClient=intraComm_ ;
521        MPI_Comm_dup(intraComm_, &intraCommServer) ;
522
523
524        clientPrimServer.push_back(new CContextClient(this, intraCommClient, interCommClient));
525        serverPrimServer.push_back(new CContextServer(this, intraCommServer, interCommServer)); 
526     
527      }
528    }
529  }
530  CATCH_DUMP_ATTR
531
[1766]532   
[697]533
[1761]534  bool CContext::eventLoop(bool enableEventsProcessing)
535  {
536    bool finished=true; 
537
538    if (client!=nullptr && !finalized) client->checkBuffers();
539   
540    for (int i = 0; i < clientPrimServer.size(); ++i)
541    {
542      if (!finalized) clientPrimServer[i]->checkBuffers();
543      if (!finalized) finished &= serverPrimServer[i]->eventLoop(enableEventsProcessing);
544    }
545
546    if (server!=nullptr) if (!finalized) finished &= server->eventLoop(enableEventsProcessing);
547 
548    return finalized && finished ;
549  }
550
[1765]551 
[1764]552 
553  void CContext::globalEventLoop(void)
554  {
555    CXios::getDaemonsManager()->eventLoop() ;
556    setCurrent(getId()) ;
557  }
[1761]558
559
560   void CContext::finalize(void)
561   TRY
562   {
[1764]563      registryOut->hierarchicalGatherRegistry() ;
564      if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
565
566      if (hasClient && !hasServer)
[1761]567      {
[1764]568        doPreTimestepOperationsForEnabledReadModeFiles(); // For now we only use server level 1 to read data
[1761]569
[1764]570        info(100)<<"DEBUG: context "<<getId()<<" Send client finalize"<<endl ;
571        client->finalize();
572        info(100)<<"DEBUG: context "<<getId()<<" Client finalize sent"<<endl ;
573        while (client->havePendingRequests()) client->checkBuffers();
574        info(100)<<"DEBUG: context "<<getId()<<" no pending request ok"<<endl ;
[1761]575        bool notifiedFinalized=false ;
576        do
577        {
578          notifiedFinalized=client->isNotifiedFinalized() ;
579        } while (!notifiedFinalized) ;
580        client->releaseBuffers();
581        info(100)<<"DEBUG: context "<<getId()<<" release client ok"<<endl ;
[1764]582      }
583      else if (hasClient && hasServer)
584      {
[1761]585         for (int i = 0; i < clientPrimServer.size(); ++i)
586         {
587           clientPrimServer[i]->finalize();
588           bool bufferReleased;
589           do
590           {
591             clientPrimServer[i]->checkBuffers();
592             bufferReleased = !clientPrimServer[i]->havePendingRequests();
593           } while (!bufferReleased);
594           
595           bool notifiedFinalized=false ;
596           do
597           {
598             notifiedFinalized=clientPrimServer[i]->isNotifiedFinalized() ;
599           } while (!notifiedFinalized) ;
600           clientPrimServer[i]->releaseBuffers();
601         }
[1764]602         closeAllFile();
[1761]603
[1764]604      }
605      else if (!hasClient && hasServer)
606      {
607        closeAllFile();
608      }
609
610      freeComms() ;
[1761]611       
[1764]612      parentServerContext_->freeComm() ;
613      finalized = true;
614      info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
[1761]615   }
[1622]616   CATCH_DUMP_ATTR
[1054]617
[1071]618   //! Free internally allocated communicators
619   void CContext::freeComms(void)
[1622]620   TRY
[1071]621   {
[1639]622     for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
623       MPI_Comm_free(&(*it));
[1071]624     comms.clear();
625   }
[1622]626   CATCH_DUMP_ATTR
[509]627
[1130]628   //! Deallocate buffers allocated by clientContexts
629   void CContext::releaseClientBuffers(void)
[1622]630   TRY
[1130]631   {
632     client->releaseBuffers();
633     for (int i = 0; i < clientPrimServer.size(); ++i)
634       clientPrimServer[i]->releaseBuffers();
635   }
[1622]636   CATCH_DUMP_ATTR
[1130]637
[1025]638   void CContext::postProcessingGlobalAttributes()
[1622]639   TRY
[300]640   {
[1144]641     if (allProcessed) return; 
[1025]642     
[1761]643    // create intercommunicator with servers.
644    // not sure it is the good place to be called here
645    createServerInterComm() ;
646
647
[1144]648     // After xml is parsed, there are some more works with post processing
649     postProcessing();
[983]650
[1144]651     // Check grid and calculate its distribution
[1232]652     checkGridEnabledFields();
653 
[1208]654     // Distribute files between secondary servers according to the data size
655     distributeFiles();
656
[1330]657     setClientServerBuffer(client, (hasClient && !hasServer));
[1255]658     for (int i = 0; i < clientPrimServer.size(); ++i)
[1330]659         setClientServerBuffer(clientPrimServer[i], true);
[300]660
[983]661     if (hasClient)
[510]662     {
[509]663      // Send all attributes of current context to server
664      this->sendAllAttributesToServer();
[459]665
[549]666      // Send all attributes of current calendar
667      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
668
[509]669      // We have enough information to send to server
[1021]670      // First of all, send all enabled files
[1232]671      sendEnabledFiles(this->enabledWriteModeFiles);
672      // We only use server-level 1 (for now) to read data
673      if (!hasServer)
674        sendEnabledFiles(this->enabledReadModeFiles);
[509]675
[1232]676      // Then, send all enabled fields     
677      sendEnabledFieldsInFiles(this->enabledWriteModeFiles);
678      if (!hasServer)
679        sendEnabledFieldsInFiles(this->enabledReadModeFiles);
[1021]680
[1239]681      // Then, check whether we have domain_ref, axis_ref or scalar_ref attached to the enabled fields
682      // If any, so send them to server
[1232]683       sendRefDomainsAxisScalars(this->enabledWriteModeFiles);
684      if (!hasServer)
685        sendRefDomainsAxisScalars(this->enabledReadModeFiles);       
[1021]686
[1239]687       // Check whether enabled fields have grid_ref, if any, send this info to server
[1237]688      sendRefGrid(this->enabledFiles);
689      // This code may be useful in the future when we want to seperate completely read and write
690      // sendRefGrid(this->enabledWriteModeFiles);
691      // if (!hasServer)
692      //   sendRefGrid(this->enabledReadModeFiles);
[1239]693     
694      // A grid of enabled fields composed of several components which must be checked then their
695      // checked attributes should be sent to server
696      sendGridComponentEnabledFieldsInFiles(this->enabledFiles); // This code can be seperated in two (one for reading, another for writing)
[1021]697
[983]698       // We have a xml tree on the server side and now, it should be also processed
[1239]699      sendPostProcessing();
[1232]700       
[1239]701      // Finally, we send information of grid itself to server
702      sendGridEnabledFieldsInFiles(this->enabledWriteModeFiles);       
703      if (!hasServer)
[1232]704        sendGridEnabledFieldsInFiles(this->enabledReadModeFiles);       
[983]705     }
[1025]706     allProcessed = true;
707   }
[1622]708   CATCH_DUMP_ATTR
[983]709
[1025]710   void CContext::sendPostProcessingGlobalAttributes()
[1622]711   TRY
[1025]712   {
[1027]713      // Use correct context client to send message
[1030]714     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
715    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1027]716     for (int i = 0; i < nbSrvPools; ++i)
717     {
718       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
719       CEventClient event(getType(),EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES);
[987]720
[1027]721       if (contextClientTmp->isServerLeader())
722       {
723         CMessage msg;
[1099]724         if (hasServer)
725           msg<<this->getIdServer(i);
726         else
727           msg<<this->getIdServer();
[1027]728         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
729         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
730           event.push(*itRank,1,msg);
731         contextClientTmp->sendEvent(event);
732       }
733       else contextClientTmp->sendEvent(event);
[1025]734     }
735   }
[1622]736   CATCH_DUMP_ATTR
[1025]737
738   void CContext::recvPostProcessingGlobalAttributes(CEventServer& event)
[1622]739   TRY
[1025]740   {
741      CBufferIn* buffer=event.subEvents.begin()->buffer;
742      string id;
743      *buffer>>id;
[1099]744      get(id)->recvPostProcessingGlobalAttributes(*buffer);
[1025]745   }
[1622]746   CATCH
[1025]747
748   void CContext::recvPostProcessingGlobalAttributes(CBufferIn& buffer)
[1622]749   TRY
[1144]750   {     
[1025]751      postProcessingGlobalAttributes();
752   }
[1622]753   CATCH_DUMP_ATTR
[1025]754
755   /*!
756   \brief Close all the context defintion and do processing data
757      After everything is well defined on client side, they will be processed and sent to server
758   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
759   all necessary information to server, from which each server can build its own database.
760   Because the role of server is to write out field data on a specific netcdf file,
761   the only information that it needs is the enabled files
762   and the active fields (fields will be written onto active files)
763   */
[1622]764
[1025]765   void CContext::closeDefinition(void)
[1622]766   TRY
[1025]767   {
[1761]768     CTimer::get("Context : close definition").resume() ;
769   
770    //
[1025]771    postProcessingGlobalAttributes();
[983]772
[1130]773    if (hasClient) sendPostProcessingGlobalAttributes();
774
775    // There are some processings that should be done after all of above. For example: check mask or index
[1025]776    this->buildFilterGraphOfEnabledFields();
777   
[1130]778     if (hasClient && !hasServer)
[509]779    {
[1130]780      buildFilterGraphOfFieldsWithReadAccess();
[1358]781      postProcessFilterGraph();
[509]782    }
[1144]783   
[1232]784    checkGridEnabledFields();   
[509]785
[1025]786    if (hasClient) this->sendProcessingGridOfEnabledFields();
[1077]787    if (hasClient) this->sendCloseDefinition();
[510]788
[584]789    // Nettoyage de l'arborescence
[983]790    if (hasClient) CleanTree(); // Only on client side??
[510]791
[598]792    if (hasClient)
793    {
794      sendCreateFileHeader();
[983]795      if (!hasServer) startPrefetchingOfEnabledReadModeFiles();
[598]796    }
[1158]797    CTimer::get("Context : close definition").suspend() ;
[300]798   }
[1622]799   CATCH_DUMP_ATTR
[509]800
[1232]801   void CContext::findAllEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[1622]802   TRY
[300]803   {
[1232]804     for (unsigned int i = 0; i < activeFiles.size(); i++)
805     (void)activeFiles[i]->getEnabledFields();
[300]806   }
[1622]807   CATCH_DUMP_ATTR
[300]808
[775]809   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
[1622]810   TRY
[775]811   {
812      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
813        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
814   }
[1622]815   CATCH_DUMP_ATTR
[775]816
[1239]817   void CContext::sendGridComponentEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[1622]818   TRY
[1239]819   {
820     int size = activeFiles.size();
821     for (int i = 0; i < size; ++i)
822     {       
823       activeFiles[i]->sendGridComponentOfEnabledFields();
824     }
825   }
[1622]826   CATCH_DUMP_ATTR
[1239]827
[1232]828   /*!
829      Send active (enabled) fields in file from a client to others
830      \param [in] activeFiles files contains enabled fields to send
831   */
832   void CContext::sendGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[1622]833   TRY
[1025]834   {
[1232]835     int size = activeFiles.size();
[1025]836     for (int i = 0; i < size; ++i)
[1099]837     {       
[1232]838       activeFiles[i]->sendGridOfEnabledFields();
[1025]839     }
840   }
[1622]841   CATCH_DUMP_ATTR
[1025]842
[1099]843   void CContext::checkGridEnabledFields()
[1622]844   TRY
[1099]845   {
[1232]846     int size = enabledFiles.size();
[1099]847     for (int i = 0; i < size; ++i)
848     {
[1232]849       enabledFiles[i]->checkGridOfEnabledFields();       
[1099]850     }
851   }
[1622]852   CATCH_DUMP_ATTR
[1025]853
[1232]854   /*!
855      Check grid of active (enabled) fields in file
856      \param [in] activeFiles files contains enabled fields whose grid needs checking
857   */
858   void CContext::checkGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[1622]859   TRY
[1232]860   {
861     int size = activeFiles.size();
862     for (int i = 0; i < size; ++i)
863     {
864       activeFiles[i]->checkGridOfEnabledFields();       
865     }
866   }
[1622]867   CATCH_DUMP_ATTR
[1232]868
869    /*!
870      Go up the hierachical tree via field_ref and do check of attributes of fields
871      This can be done in a client then all computed information will be sent from this client to others
872      \param [in] sendToServer Flag to indicate whether calculated information will be sent
873   */
[823]874   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
[1622]875   TRY
[823]876   {
877     int size = this->enabledFiles.size();
878     for (int i = 0; i < size; ++i)
879     {
880       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
881     }
882
883     for (int i = 0; i < size; ++i)
884     {
885       this->enabledFiles[i]->generateNewTransformationGridDest();
886     }
887   }
[1622]888   CATCH_DUMP_ATTR
[823]889
[1232]890    /*!
891      Go up the hierachical tree via field_ref and do check of attributes of fields.
892      The transformation can be done in this step.
893      All computed information will be sent from this client to others.
894      \param [in] sendToServer Flag to indicate whether calculated information will be sent
895   */
[1129]896   void CContext::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
[1622]897   TRY
[300]898   {
[509]899     int size = this->enabledFiles.size();
900     for (int i = 0; i < size; ++i)
901     {
[1129]902       this->enabledFiles[i]->solveAllRefOfEnabledFieldsAndTransform(sendToServer);
[509]903     }
[300]904   }
[1622]905   CATCH_DUMP_ATTR
[300]906
[640]907   void CContext::buildFilterGraphOfEnabledFields()
[1622]908   TRY
[640]909   {
910     int size = this->enabledFiles.size();
911     for (int i = 0; i < size; ++i)
912     {
913       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
914     }
915   }
[1622]916   CATCH_DUMP_ATTR
[640]917
[1358]918   void CContext::postProcessFilterGraph()
[1622]919   TRY
[1358]920   {
921     int size = enabledFiles.size();
922     for (int i = 0; i < size; ++i)
923     {
924        enabledFiles[i]->postProcessFilterGraph();
925     }
926   }
[1622]927   CATCH_DUMP_ATTR
[1358]928
[598]929   void CContext::startPrefetchingOfEnabledReadModeFiles()
[1622]930   TRY
[598]931   {
932     int size = enabledReadModeFiles.size();
933     for (int i = 0; i < size; ++i)
934     {
935        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
936     }
937   }
[1622]938   CATCH_DUMP_ATTR
[598]939
[1358]940   void CContext::doPreTimestepOperationsForEnabledReadModeFiles()
[1622]941   TRY
[1358]942   {
943     int size = enabledReadModeFiles.size();
944     for (int i = 0; i < size; ++i)
945     {
946        enabledReadModeFiles[i]->doPreTimestepOperationsForEnabledReadModeFields();
947     }
948   }
[1622]949   CATCH_DUMP_ATTR
[1358]950
[1318]951   void CContext::doPostTimestepOperationsForEnabledReadModeFiles()
[1622]952   TRY
[598]953   {
954     int size = enabledReadModeFiles.size();
955     for (int i = 0; i < size; ++i)
956     {
[1318]957        enabledReadModeFiles[i]->doPostTimestepOperationsForEnabledReadModeFields();
[598]958     }
959   }
[1622]960   CATCH_DUMP_ATTR
[598]961
[593]962  void CContext::findFieldsWithReadAccess(void)
[1622]963  TRY
[593]964  {
965    fieldsWithReadAccess.clear();
966    const vector<CField*> allFields = CField::getAll();
967    for (size_t i = 0; i < allFields.size(); ++i)
968    {
[740]969      CField* field = allFields[i];
970
971      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
972        field->read_access = true;
973      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
974        fieldsWithReadAccess.push_back(field);
[593]975    }
976  }
[1622]977  CATCH_DUMP_ATTR
[593]978
979  void CContext::solveAllRefOfFieldsWithReadAccess()
[1622]980  TRY
[593]981  {
982    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
983      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
984  }
[1622]985  CATCH_DUMP_ATTR
[593]986
[640]987  void CContext::buildFilterGraphOfFieldsWithReadAccess()
[1622]988  TRY
[640]989  {
990    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
991      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
992  }
[1622]993  CATCH_DUMP_ATTR
[640]994
[445]995   void CContext::solveAllInheritance(bool apply)
[1622]996   TRY
[300]997   {
998     // Résolution des héritages descendants (càd des héritages de groupes)
999     // pour chacun des contextes.
[445]1000      solveDescInheritance(apply);
[300]1001
1002     // Résolution des héritages par référence au niveau des fichiers.
[549]1003      const vector<CFile*> allFiles=CFile::getAll();
[540]1004      const vector<CGrid*> allGrids= CGrid::getAll();
[300]1005
[983]1006      if (hasClient && !hasServer)
1007      //if (hasClient)
[540]1008      {
[510]1009        for (unsigned int i = 0; i < allFiles.size(); i++)
1010          allFiles[i]->solveFieldRefInheritance(apply);
[540]1011      }
1012
1013      unsigned int vecSize = allGrids.size();
1014      unsigned int i = 0;
1015      for (i = 0; i < vecSize; ++i)
1016        allGrids[i]->solveDomainAxisRefInheritance(apply);
1017
[300]1018   }
[1622]1019  CATCH_DUMP_ATTR
[300]1020
1021   void CContext::findEnabledFiles(void)
[1622]1022   TRY
[300]1023   {
[347]1024      const std::vector<CFile*> allFiles = CFile::getAll();
[1158]1025      const CDate& initDate = calendar->getInitDate();
[300]1026
1027      for (unsigned int i = 0; i < allFiles.size(); i++)
1028         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
[430]1029         {
[300]1030            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
[1158]1031            {
[1489]1032              if (allFiles[i]->output_freq.isEmpty())
[1488]1033              {
1034                 ERROR("CContext::findEnabledFiles()",
1035                     << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1036                     <<" \".")
1037              }
[1158]1038              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1039              {
1040                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1041                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1042                    <<"\" is less than the time step. File will not be written."<<endl;
1043              }
1044              else
[300]1045               enabledFiles.push_back(allFiles[i]);
[1158]1046            }
[430]1047         }
[1158]1048         else
1049         {
[1489]1050           if (allFiles[i]->output_freq.isEmpty())
[1488]1051           {
1052              ERROR("CContext::findEnabledFiles()",
1053                  << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1054                  <<" \".")
1055           }
[1158]1056           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1057           {
1058             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1059                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1060                 <<"\" is less than the time step. File will not be written."<<endl;
1061           }
1062           else
1063             enabledFiles.push_back(allFiles[i]); // otherwise true by default
1064         }
[300]1065
1066      if (enabledFiles.size() == 0)
1067         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
1068               << getId() << "\" !");
[1021]1069
[300]1070   }
[1622]1071   CATCH_DUMP_ATTR
[300]1072
[1208]1073   void CContext::distributeFiles(void)
[1622]1074   TRY
[1208]1075   {
[1349]1076     bool distFileMemory=false ;
1077     distFileMemory=CXios::getin<bool>("server2_dist_file_memory", distFileMemory);
1078
1079     if (distFileMemory) distributeFileOverMemoryBandwith() ;
1080     else distributeFileOverBandwith() ;
1081   }
[1622]1082   CATCH_DUMP_ATTR
[1349]1083
1084   void CContext::distributeFileOverBandwith(void)
[1622]1085   TRY
[1349]1086   {
[1215]1087     double eps=std::numeric_limits<double>::epsilon()*10 ;
1088     
[1208]1089     // If primary server
1090     if (hasServer && hasClient)
1091     {
[1349]1092       std::ofstream ofs(("distribute_file_"+getId()+".dat").c_str(), std::ofstream::out);
[1212]1093       int nbPools = clientPrimServer.size();
1094
[1208]1095       // (1) Find all enabled files in write mode
[1232]1096       // for (int i = 0; i < this->enabledFiles.size(); ++i)
1097       // {
1098       //   if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1099       //    enabledWriteModeFiles.push_back(enabledFiles[i]);
1100       // }
[1208]1101
1102       // (2) Estimate the data volume for each file
1103       int size = this->enabledWriteModeFiles.size();
[1215]1104       std::vector<std::pair<double, CFile*> > dataSizeMap;
1105       double dataPerPool = 0;
1106       int nfield=0 ;
[1349]1107       ofs<<size<<endl ;
[1208]1108       for (size_t i = 0; i < size; ++i)
1109       {
1110         CFile* file = this->enabledWriteModeFiles[i];
[1349]1111         ofs<<file->getId()<<endl ;
[1215]1112         StdSize dataSize=0;
[1208]1113         std::vector<CField*> enabledFields = file->getEnabledFields();
1114         size_t numEnabledFields = enabledFields.size();
[1349]1115         ofs<<numEnabledFields<<endl ;
1116         for (size_t j = 0; j < numEnabledFields; ++j)
1117         {
1118           dataSize += enabledFields[j]->getGlobalWrittenSize() ;
1119           ofs<<enabledFields[j]->grid->getId()<<endl ;
1120           ofs<<enabledFields[j]->getGlobalWrittenSize()<<endl ;
1121         }
[1215]1122         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1123         double dataSizeSec= dataSize/ outFreqSec;
[1349]1124         ofs<<dataSizeSec<<endl ;
[1215]1125         nfield++ ;
1126// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
1127         dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
1128         dataPerPool += dataSizeSec;
[1208]1129       }
[1212]1130       dataPerPool /= nbPools;
[1208]1131       std::sort(dataSizeMap.begin(), dataSizeMap.end());
1132
[1212]1133       // (3) Assign contextClient to each enabled file
[1215]1134
1135       std::multimap<double,int> poolDataSize ;
1136// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
1137
1138       int j;
1139       double dataSize ;
1140       for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
1141             
[1212]1142       for (int i = dataSizeMap.size()-1; i >= 0; --i)
[1208]1143       {
[1215]1144         dataSize=(*poolDataSize.begin()).first ;
1145         j=(*poolDataSize.begin()).second ;
1146         dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
1147         dataSize+=dataSizeMap[i].first;
1148         poolDataSize.erase(poolDataSize.begin()) ;
1149         poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
[1208]1150       }
[1212]1151
[1215]1152       for (std::multimap<double,int>:: iterator it=poolDataSize.begin() ; it!=poolDataSize.end(); ++it) info(30)<<"Load Balancing for servers (perfect=1) : "<<it->second<<" :  ratio "<<it->first*1./dataPerPool<<endl ;
1153 
[1212]1154       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
[1232]1155       {
1156         enabledReadModeFiles[i]->setContextClient(client);         
1157       }
[1208]1158     }
1159     else
1160     {
1161       for (int i = 0; i < this->enabledFiles.size(); ++i)
1162         enabledFiles[i]->setContextClient(client);
1163     }
1164   }
[1622]1165   CATCH_DUMP_ATTR
[1208]1166
[1349]1167   void CContext::distributeFileOverMemoryBandwith(void)
[1622]1168   TRY
[1349]1169   {
1170     // If primary server
1171     if (hasServer && hasClient)
1172     {
1173       int nbPools = clientPrimServer.size();
1174       double ratio=0.5 ;
1175       ratio=CXios::getin<double>("server2_dist_file_memory_ratio", ratio);
1176
1177       int nFiles = this->enabledWriteModeFiles.size();
1178       vector<SDistFile> files(nFiles);
1179       vector<SDistGrid> grids;
1180       map<string,int> gridMap ;
1181       string gridId; 
1182       int gridIndex=0 ;
1183
1184       for (size_t i = 0; i < nFiles; ++i)
1185       {
1186         StdSize dataSize=0;
1187         CFile* file = this->enabledWriteModeFiles[i];
1188         std::vector<CField*> enabledFields = file->getEnabledFields();
1189         size_t numEnabledFields = enabledFields.size();
1190
1191         files[i].id_=file->getId() ;
1192         files[i].nbGrids_=numEnabledFields;
1193         files[i].assignedGrid_ = new int[files[i].nbGrids_] ;
1194         
1195         for (size_t j = 0; j < numEnabledFields; ++j)
1196         {
1197           gridId=enabledFields[j]->grid->getId() ;
1198           if (gridMap.find(gridId)==gridMap.end())
1199           {
1200              gridMap[gridId]=gridIndex  ;
1201              SDistGrid newGrid; 
1202              grids.push_back(newGrid) ;
1203              gridIndex++ ;
1204           }
1205           files[i].assignedGrid_[j]=gridMap[gridId] ;
1206           grids[files[i].assignedGrid_[j]].size_=enabledFields[j]->getGlobalWrittenSize() ;
1207           dataSize += enabledFields[j]->getGlobalWrittenSize() ; // usefull
1208         }
1209         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1210         files[i].bandwith_= dataSize/ outFreqSec ;
1211       }
1212
1213       double bandwith=0 ;
1214       double memory=0 ;
1215   
1216       for(int i=0; i<nFiles; i++)  bandwith+=files[i].bandwith_ ;
1217       for(int i=0; i<nFiles; i++)  files[i].bandwith_ = files[i].bandwith_/bandwith * ratio ;
1218
1219       for(int i=0; i<grids.size(); i++)  memory+=grids[i].size_ ;
1220       for(int i=0; i<grids.size(); i++)  grids[i].size_ = grids[i].size_ / memory * (1.0-ratio) ;
1221       
1222       distributeFileOverServer2(nbPools, grids.size(), &grids[0], nFiles, &files[0]) ;
1223
1224       vector<double> memorySize(nbPools,0.) ;
1225       vector< set<int> > serverGrids(nbPools) ;
1226       vector<double> bandwithSize(nbPools,0.) ;
1227       
1228       for (size_t i = 0; i < nFiles; ++i)
1229       {
1230         bandwithSize[files[i].assignedServer_] += files[i].bandwith_* bandwith /ratio ;
1231         for(int j=0 ; j<files[i].nbGrids_;j++)
1232         {
1233           if (serverGrids[files[i].assignedServer_].find(files[i].assignedGrid_[j]) == serverGrids[files[i].assignedServer_].end())
1234           {
1235             memorySize[files[i].assignedServer_]+= grids[files[i].assignedGrid_[j]].size_ * memory / (1.0-ratio);
1236             serverGrids[files[i].assignedServer_].insert(files[i].assignedGrid_[j]) ;
1237           }
1238         }
1239         enabledWriteModeFiles[i]->setContextClient(clientPrimServer[files[i].assignedServer_]) ;
1240         delete [] files[i].assignedGrid_ ;
1241       }
1242
1243       for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned file bandwith "<<bandwithSize[i]*86400.*4./1024/1024.<<" Mb / days"<<endl ;
1244       for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned grid memory "<<memorySize[i]*100/1024./1024.<<" Mb"<<endl ;
1245
1246
1247       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
1248       {
1249         enabledReadModeFiles[i]->setContextClient(client);         
1250       }
1251
1252   }
1253   else
1254   {
1255     for (int i = 0; i < this->enabledFiles.size(); ++i)
1256        enabledFiles[i]->setContextClient(client);
1257   }
1258}
[1622]1259   CATCH_DUMP_ATTR
[1349]1260
[1232]1261   /*!
1262      Find all files in write mode
1263   */
1264   void CContext::findEnabledWriteModeFiles(void)
[1622]1265   TRY
[1232]1266   {
1267     int size = this->enabledFiles.size();
1268     for (int i = 0; i < size; ++i)
1269     {
1270       if (enabledFiles[i]->mode.isEmpty() || 
1271          (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1272        enabledWriteModeFiles.push_back(enabledFiles[i]);
1273     }
1274   }
[1622]1275   CATCH_DUMP_ATTR
[1232]1276
1277   /*!
1278      Find all files in read mode
1279   */
[598]1280   void CContext::findEnabledReadModeFiles(void)
[1622]1281   TRY
[598]1282   {
1283     int size = this->enabledFiles.size();
1284     for (int i = 0; i < size; ++i)
1285     {
1286       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
1287        enabledReadModeFiles.push_back(enabledFiles[i]);
1288     }
1289   }
[1622]1290   CATCH_DUMP_ATTR
[598]1291
[300]1292   void CContext::closeAllFile(void)
[1622]1293   TRY
[300]1294   {
[347]1295     std::vector<CFile*>::const_iterator
[300]1296            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
[509]1297
[300]1298     for (; it != end; it++)
1299     {
1300       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
1301       (*it)->close();
1302     }
1303   }
[1622]1304   CATCH_DUMP_ATTR
[509]1305
1306   /*!
1307   \brief Dispatch event received from client
1308      Whenever a message is received in buffer of server, it will be processed depending on
1309   its event type. A new event type should be added in the switch list to make sure
1310   it processed on server side.
1311   \param [in] event: Received message
1312   */
[300]1313   bool CContext::dispatchEvent(CEventServer& event)
[1622]1314   TRY
[300]1315   {
[509]1316
[549]1317      if (SuperClass::dispatchEvent(event)) return true;
[300]1318      else
1319      {
1320        switch(event.type)
1321        {
1322           case EVENT_ID_CLOSE_DEFINITION :
[549]1323             recvCloseDefinition(event);
1324             return true;
1325             break;
[584]1326           case EVENT_ID_UPDATE_CALENDAR:
[549]1327             recvUpdateCalendar(event);
1328             return true;
1329             break;
[300]1330           case EVENT_ID_CREATE_FILE_HEADER :
[549]1331             recvCreateFileHeader(event);
1332             return true;
1333             break;
[509]1334           case EVENT_ID_POST_PROCESS:
[549]1335             recvPostProcessing(event);
1336             return true;
[697]1337            case EVENT_ID_SEND_REGISTRY:
1338             recvRegistry(event);
1339             return true;
[1025]1340             break;
1341            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
1342             recvPostProcessingGlobalAttributes(event);
1343             return true;
1344             break;
1345            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
1346             recvProcessingGridOfEnabledFields(event);
1347             return true;
1348             break;
[300]1349           default :
1350             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
[549]1351                    <<"Unknown Event");
1352           return false;
[300]1353         }
1354      }
1355   }
[1622]1356   CATCH
[509]1357
1358   //! Client side: Send a message to server to make it close
[300]1359   void CContext::sendCloseDefinition(void)
[1622]1360   TRY
[300]1361   {
[987]1362     // Use correct context client to send message
[1030]1363     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1364     for (int i = 0; i < nbSrvPools; ++i)
[300]1365     {
[1009]1366       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1367       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1368       if (contextClientTmp->isServerLeader())
1369       {
1370         CMessage msg;
1371         if (hasServer)
1372           msg<<this->getIdServer(i);
1373         else
1374           msg<<this->getIdServer();
1375         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1376         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1377           event.push(*itRank,1,msg);
1378         contextClientTmp->sendEvent(event);
1379       }
1380       else contextClientTmp->sendEvent(event);
[300]1381     }
1382   }
[1622]1383   CATCH_DUMP_ATTR
[509]1384
1385   //! Server side: Receive a message of client announcing a context close
[300]1386   void CContext::recvCloseDefinition(CEventServer& event)
[1622]1387   TRY
[300]1388   {
1389      CBufferIn* buffer=event.subEvents.begin()->buffer;
1390      string id;
[549]1391      *buffer>>id;
[509]1392      get(id)->closeDefinition();
[300]1393   }
[1622]1394   CATCH
[509]1395
1396   //! Client side: Send a message to update calendar in each time step
[300]1397   void CContext::sendUpdateCalendar(int step)
[1622]1398   TRY
[300]1399   {
[987]1400     // Use correct context client to send message
[1030]1401    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1402     for (int i = 0; i < nbSrvPools; ++i)
1403     {
1404       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1405       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
[987]1406
[1009]1407         if (contextClientTmp->isServerLeader())
1408         {
1409           CMessage msg;
1410           if (hasServer)
1411             msg<<this->getIdServer(i)<<step;
1412           else
1413             msg<<this->getIdServer()<<step;
1414           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1415           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1416             event.push(*itRank,1,msg);
1417           contextClientTmp->sendEvent(event);
1418         }
1419         else contextClientTmp->sendEvent(event);
1420     }
[300]1421   }
[1622]1422   CATCH_DUMP_ATTR
[509]1423
1424   //! Server side: Receive a message of client annoucing calendar update
[300]1425   void CContext::recvUpdateCalendar(CEventServer& event)
[1622]1426   TRY
[300]1427   {
1428      CBufferIn* buffer=event.subEvents.begin()->buffer;
1429      string id;
[549]1430      *buffer>>id;
1431      get(id)->recvUpdateCalendar(*buffer);
[300]1432   }
[1622]1433   CATCH
[509]1434
1435   //! Server side: Receive a message of client annoucing calendar update
[300]1436   void CContext::recvUpdateCalendar(CBufferIn& buffer)
[1622]1437   TRY
[300]1438   {
[549]1439      int step;
1440      buffer>>step;
1441      updateCalendar(step);
[987]1442      if (hasClient && hasServer)
1443      {       
1444        sendUpdateCalendar(step);
1445      }
[300]1446   }
[1622]1447   CATCH_DUMP_ATTR
[509]1448
1449   //! Client side: Send a message to create header part of netcdf file
[300]1450   void CContext::sendCreateFileHeader(void)
[1622]1451   TRY
[300]1452   {
[987]1453     // Use correct context client to send message
[1030]1454     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1455     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1456     for (int i = 0; i < nbSrvPools; ++i)
1457     {
1458       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1459       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
[983]1460
[1009]1461       if (contextClientTmp->isServerLeader())
1462       {
1463         CMessage msg;
1464         if (hasServer)
1465           msg<<this->getIdServer(i);
1466         else
1467           msg<<this->getIdServer();
1468         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1469         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1470           event.push(*itRank,1,msg) ;
1471         contextClientTmp->sendEvent(event);
1472       }
1473       else contextClientTmp->sendEvent(event);
[300]1474     }
1475   }
[1622]1476   CATCH_DUMP_ATTR
[509]1477
1478   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
[300]1479   void CContext::recvCreateFileHeader(CEventServer& event)
[1622]1480   TRY
[300]1481   {
1482      CBufferIn* buffer=event.subEvents.begin()->buffer;
1483      string id;
[549]1484      *buffer>>id;
1485      get(id)->recvCreateFileHeader(*buffer);
[300]1486   }
[1622]1487   CATCH
[509]1488
1489   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
[300]1490   void CContext::recvCreateFileHeader(CBufferIn& buffer)
[1622]1491   TRY
[300]1492   {
[987]1493      if (!hasClient && hasServer) 
1494        createFileHeader();
[300]1495   }
[1622]1496   CATCH_DUMP_ATTR
[509]1497
1498   //! Client side: Send a message to do some post processing on server
[1025]1499   void CContext::sendProcessingGridOfEnabledFields()
[1622]1500   TRY
[1025]1501   {
1502      // Use correct context client to send message
[1030]1503     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1027]1504     for (int i = 0; i < nbSrvPools; ++i)
1505     {
1506       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1507       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
[1025]1508
[1027]1509       if (contextClientTmp->isServerLeader())
1510       {
1511         CMessage msg;
[1099]1512         if (hasServer)
1513           msg<<this->getIdServer(i);
1514         else
1515           msg<<this->getIdServer();
[1027]1516         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1517         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1518           event.push(*itRank,1,msg);
1519         contextClientTmp->sendEvent(event);
1520       }
1521       else contextClientTmp->sendEvent(event);
[1025]1522     }
1523   }
[1622]1524   CATCH_DUMP_ATTR
[1025]1525
1526   //! Server side: Receive a message to do some post processing
1527   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
[1622]1528   TRY
[1025]1529   {
1530      CBufferIn* buffer=event.subEvents.begin()->buffer;
1531      string id;
[1144]1532      *buffer>>id;     
[1025]1533   }
[1622]1534   CATCH
[1025]1535
1536   //! Client side: Send a message to do some post processing on server
[509]1537   void CContext::sendPostProcessing()
[1622]1538   TRY
[509]1539   {
[987]1540      // Use correct context client to send message
[1030]1541     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1542     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1543     for (int i = 0; i < nbSrvPools; ++i)
[509]1544     {
[1009]1545       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1546       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1547       if (contextClientTmp->isServerLeader())
1548       {
1549         CMessage msg;
1550         if (hasServer)
1551           msg<<this->getIdServer(i);
1552         else
1553           msg<<this->getIdServer();
1554         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1555         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
[987]1556         event.push(*itRank,1,msg);
[1009]1557         contextClientTmp->sendEvent(event);
1558       }
1559       else contextClientTmp->sendEvent(event);
[509]1560     }
1561   }
[1622]1562   CATCH_DUMP_ATTR
[509]1563
1564   //! Server side: Receive a message to do some post processing
1565   void CContext::recvPostProcessing(CEventServer& event)
[1622]1566   TRY
[509]1567   {
1568      CBufferIn* buffer=event.subEvents.begin()->buffer;
1569      string id;
1570      *buffer>>id;
1571      get(id)->recvPostProcessing(*buffer);
1572   }
[1622]1573   CATCH
[509]1574
1575   //! Server side: Receive a message to do some post processing
1576   void CContext::recvPostProcessing(CBufferIn& buffer)
[1622]1577   TRY
[509]1578   {
[549]1579      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
[509]1580      postProcessing();
1581   }
[1622]1582   CATCH_DUMP_ATTR
[509]1583
[1761]1584   void CContext::setIdServer(const StdString& idServer)
1585   TRY
1586   {
1587      idServer_=idServer ;
1588   }
1589   CATCH_DUMP_ATTR
1590
1591   
[511]1592   const StdString& CContext::getIdServer()
[1622]1593   TRY
[511]1594   {
[1761]1595      return idServer_;
1596   }
1597   CATCH_DUMP_ATTR
1598
1599   const StdString& CContext::getIdServer(const int i)
1600   TRY
1601   {
1602//     return idServer_ + std::to_string(static_cast<unsigned long long>(i));
1603      return primServerId_[i] ;
1604   }
1605   CATCH_DUMP_ATTR
1606
1607/*
1608   const StdString& CContext::getIdServer()
1609   TRY
1610   {
[511]1611      if (hasClient)
1612      {
1613        idServer_ = this->getId();
1614        idServer_ += "_server";
1615        return idServer_;
1616      }
1617      if (hasServer) return (this->getId());
1618   }
[1622]1619   CATCH_DUMP_ATTR
[511]1620
[1009]1621   const StdString& CContext::getIdServer(const int i)
[1622]1622   TRY
[1009]1623   {
1624     idServer_ = this->getId();
1625     idServer_ += "_server_";
[1542]1626     idServer_ += std::to_string(static_cast<unsigned long long>(i));
[1009]1627     return idServer_;
1628   }
[1622]1629   CATCH_DUMP_ATTR
[1761]1630*/
[1009]1631
[1761]1632
[509]1633   /*!
1634   \brief Do some simple post processings after parsing xml file
1635      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1636   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1637   which will be written out into netcdf files, are processed
1638   */
1639   void CContext::postProcessing()
[1622]1640   TRY
[509]1641   {
1642     if (isPostProcessed) return;
1643
[549]1644      // Make sure the calendar was correctly created
1645      if (!calendar)
1646        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1647      else if (calendar->getTimeStep() == NoneDu)
1648        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
[550]1649      // Calendar first update to set the current date equals to the start date
1650      calendar->update(0);
[509]1651
1652      // Find all inheritance in xml structure
1653      this->solveAllInheritance();
1654
[992]1655//      ShowTree(info(10));
[983]1656
[676]1657      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1658      // Warning: This must be done after solving the inheritance and before the rest of post-processing
[1025]1659      checkAxisDomainsGridsEligibilityForCompressedOutput();     
[676]1660
[711]1661      // Check if some automatic time series should be generated
[1144]1662      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
[711]1663
[1025]1664      // The timeseries should only be prepared in client
1665      if (hasClient && !hasServer) prepareTimeseries();
1666
[509]1667      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
[1232]1668      findEnabledFiles();
1669      findEnabledWriteModeFiles();
1670      findEnabledReadModeFiles();
1671
[1025]1672      // For now, only read files with client and only one level server
[1232]1673      // if (hasClient && !hasServer) findEnabledReadModeFiles();     
[509]1674
[1232]1675      // Find all enabled fields of each file     
1676      findAllEnabledFieldsInFiles(this->enabledWriteModeFiles);
1677      findAllEnabledFieldsInFiles(this->enabledReadModeFiles);
1678
[1025]1679      // For now, only read files with client and only one level server
[1232]1680      // if (hasClient && !hasServer)
1681      //   findAllEnabledFieldsInFiles(this->enabledReadModeFiles);     
[509]1682
[1144]1683      if (hasClient && !hasServer)
1684      {
[1232]1685        initReadFiles();
1686        // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1687        this->readAttributesOfEnabledFieldsInReadModeFiles();
[1144]1688      }
1689
[823]1690      // Only search and rebuild all reference objects of enable fields, don't transform
[1099]1691      this->solveOnlyRefOfEnabledFields(false);
[823]1692
[1099]1693      // Search and rebuild all reference object of enabled fields, and transform
[1129]1694      this->solveAllRefOfEnabledFieldsAndTransform(false);
[1099]1695
[593]1696      // Find all fields with read access from the public API
[1025]1697      if (hasClient && !hasServer) findFieldsWithReadAccess();
[593]1698      // and solve the all reference for them
[1025]1699      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
[593]1700
[509]1701      isPostProcessed = true;
1702   }
[1622]1703   CATCH_DUMP_ATTR
[509]1704
[917]1705   /*!
1706    * Compute the required buffer size to send the attributes (mostly those grid related).
1707    * \param maxEventSize [in/out] the size of the bigger event for each connected server
[1330]1708    * \param [in] contextClient
1709    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1710      This flag is only true for client and server-1 for communication with server-2
[917]1711    */
[1330]1712   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize,
1713                                                           CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
[1622]1714   TRY
[509]1715   {
[1372]1716         // As calendar attributes are sent even if there are no active files or fields, maps are initialized according the size of calendar attributes
1717     std::map<int, StdSize> attributesSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1718     maxEventSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
[731]1719
[1370]1720     std::vector<CFile*>& fileList = this->enabledFiles;
1721     size_t numEnabledFiles = fileList.size();
1722     for (size_t i = 0; i < numEnabledFiles; ++i)
[731]1723     {
[1370]1724//         CFile* file = this->enabledWriteModeFiles[i];
1725        CFile* file = fileList[i];
1726        std::vector<CField*> enabledFields = file->getEnabledFields();
1727        size_t numEnabledFields = enabledFields.size();
1728        for (size_t j = 0; j < numEnabledFields; ++j)
1729        {
1730          const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient, bufferForWriting);
1731          std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1732          for (; it != itE; ++it)
1733          {
1734                     // If attributesSize[it->first] does not exist, it will be zero-initialized
1735                     // so we can use it safely without checking for its existence
1736             if (attributesSize[it->first] < it->second)
1737                           attributesSize[it->first] = it->second;
[917]1738
[1370]1739                     if (maxEventSize[it->first] < it->second)
1740                           maxEventSize[it->first] = it->second;
1741          }
1742        }
[731]1743     }
1744     return attributesSize;
1745   }
[1622]1746   CATCH_DUMP_ATTR
[731]1747
[917]1748   /*!
1749    * Compute the required buffer size to send the fields data.
1750    * \param maxEventSize [in/out] the size of the bigger event for each connected server
[1330]1751    * \param [in] contextClient
1752    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1753      This flag is only true for client and server-1 for communication with server-2
[917]1754    */
[1330]1755   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize,
1756                                                      CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
[1622]1757   TRY
[731]1758   {
[730]1759     std::map<int, StdSize> dataSize;
[509]1760
1761     // Find all reference domain and axis of all active fields
[1330]1762     std::vector<CFile*>& fileList = bufferForWriting ? this->enabledWriteModeFiles : this->enabledReadModeFiles;
1763     size_t numEnabledFiles = fileList.size();
[730]1764     for (size_t i = 0; i < numEnabledFiles; ++i)
[509]1765     {
[1330]1766       CFile* file = fileList[i];
[1193]1767       if (file->getContextClient() == contextClient)
[1184]1768       {
[1370]1769         std::vector<CField*> enabledFields = file->getEnabledFields();
1770         size_t numEnabledFields = enabledFields.size();
1771         for (size_t j = 0; j < numEnabledFields; ++j)
[509]1772         {
[1370]1773           // const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1774           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize(contextClient,bufferForWriting);
1775           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1776           for (; it != itE; ++it)
[509]1777           {
[1370]1778             // If dataSize[it->first] does not exist, it will be zero-initialized
1779             // so we can use it safely without checking for its existance
1780                 if (CXios::isOptPerformance)
1781               dataSize[it->first] += it->second;
1782             else if (dataSize[it->first] < it->second)
1783               dataSize[it->first] = it->second;
[917]1784
[1370]1785                 if (maxEventSize[it->first] < it->second)
1786               maxEventSize[it->first] = it->second;
[598]1787           }
[509]1788         }
1789       }
1790     }
[730]1791     return dataSize;
[509]1792   }
[1622]1793   CATCH_DUMP_ATTR
[509]1794
1795   //! Client side: Send infomation of active files (files are enabled to write out)
[1232]1796   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
[1622]1797   TRY
[509]1798   {
[1232]1799     int size = activeFiles.size();
[509]1800
1801     // In a context, each type has a root definition, e.g: axis, domain, field.
1802     // Every object must be a child of one of these root definition. In this case
1803     // all new file objects created on server must be children of the root "file_definition"
1804     StdString fileDefRoot("file_definition");
1805     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
[1158]1806
[509]1807     for (int i = 0; i < size; ++i)
1808     {
[1232]1809       CFile* f = activeFiles[i];
1810       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1811       f->sendAllAttributesToServer(f->getContextClient());
1812       f->sendAddAllVariables(f->getContextClient());
[509]1813     }
1814   }
[1622]1815   CATCH_DUMP_ATTR
[509]1816
1817   //! Client side: Send information of active fields (ones are written onto files)
[1232]1818   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[1622]1819   TRY
[509]1820   {
[1232]1821     int size = activeFiles.size();
[509]1822     for (int i = 0; i < size; ++i)
1823     {
[1232]1824       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
[509]1825     }
1826   }
[1622]1827   CATCH_DUMP_ATTR
[509]1828
[676]1829   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1830   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
[1622]1831   TRY
[676]1832   {
1833     if (!hasClient) return;
1834
1835     const vector<CAxis*> allAxis = CAxis::getAll();
1836     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1837       (*it)->checkEligibilityForCompressedOutput();
1838
1839     const vector<CDomain*> allDomains = CDomain::getAll();
1840     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1841       (*it)->checkEligibilityForCompressedOutput();
1842
1843     const vector<CGrid*> allGrids = CGrid::getAll();
1844     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1845       (*it)->checkEligibilityForCompressedOutput();
1846   }
[1622]1847   CATCH_DUMP_ATTR
[676]1848
[711]1849   //! Client side: Prepare the timeseries by adding the necessary files
1850   void CContext::prepareTimeseries()
[1622]1851   TRY
[711]1852   {
1853     if (!hasClient) return;
1854
1855     const std::vector<CFile*> allFiles = CFile::getAll();
1856     for (size_t i = 0; i < allFiles.size(); i++)
1857     {
1858       CFile* file = allFiles[i];
1859
[1158]1860       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1861       for (size_t k = 0; k < vars.size(); k++)
1862       {
1863         CVariable* var = vars[k];
1864
1865         if (var->ts_target.isEmpty()
1866              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1867           fileVars.push_back(var);
1868
1869         if (!var->ts_target.isEmpty()
1870              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1871           fieldVars.push_back(var);
1872       }
1873
[711]1874       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1875       {
[1158]1876         StdString fileNameStr("%file_name%") ;
1877         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1878         
1879         StdString fileName=file->getFileOutputName();
1880         size_t pos=tsPrefix.find(fileNameStr) ;
1881         while (pos!=std::string::npos)
1882         {
1883           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1884           pos=tsPrefix.find(fileNameStr) ;
1885         }
1886       
[711]1887         const std::vector<CField*> allFields = file->getAllFields();
1888         for (size_t j = 0; j < allFields.size(); j++)
1889         {
1890           CField* field = allFields[j];
1891
1892           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1893           {
1894             CFile* tsFile = CFile::create();
1895             tsFile->duplicateAttributes(file);
1896
[1158]1897             // Add variables originating from file and targeted to timeserie file
1898             for (size_t k = 0; k < fileVars.size(); k++)
1899               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1900
1901           
[711]1902             tsFile->name = tsPrefix + "_";
1903             if (!field->name.isEmpty())
1904               tsFile->name.get() += field->name;
1905             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1906               tsFile->name.get() += field->field_ref;
1907             else
1908               tsFile->name.get() += field->getId();
1909
1910             if (!field->ts_split_freq.isEmpty())
1911               tsFile->split_freq = field->ts_split_freq;
1912
1913             CField* tsField = tsFile->addField();
1914             tsField->field_ref = field->getId();
1915
[1158]1916             // Add variables originating from file and targeted to timeserie field
1917             for (size_t k = 0; k < fieldVars.size(); k++)
1918               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1919
1920             vars = field->getAllVariables();
1921             for (size_t k = 0; k < vars.size(); k++)
1922             {
1923               CVariable* var = vars[k];
1924
1925               // Add variables originating from field and targeted to timeserie field
1926               if (var->ts_target.isEmpty()
1927                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1928                 tsField->getVirtualVariableGroup()->addChild(var);
1929
1930               // Add variables originating from field and targeted to timeserie file
1931               if (!var->ts_target.isEmpty()
1932                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1933                 tsFile->getVirtualVariableGroup()->addChild(var);
1934             }
1935
[711]1936             tsFile->solveFieldRefInheritance(true);
1937
1938             if (file->timeseries == CFile::timeseries_attr::exclusive)
1939               field->enabled = false;
1940           }
1941         }
1942
1943         // Finally disable the original file is need be
1944         if (file->timeseries == CFile::timeseries_attr::only)
1945          file->enabled = false;
1946       }
1947     }
1948   }
[1622]1949   CATCH_DUMP_ATTR
[711]1950
[509]1951   //! Client side: Send information of reference grid of active fields
[1232]1952   void CContext::sendRefGrid(const std::vector<CFile*>& activeFiles)
[1622]1953   TRY
[509]1954   {
1955     std::set<StdString> gridIds;
[1232]1956     int sizeFile = activeFiles.size();
[509]1957     CFile* filePtr(NULL);
1958
1959     // Firstly, find all reference grids of all active fields
1960     for (int i = 0; i < sizeFile; ++i)
1961     {
[1232]1962       filePtr = activeFiles[i];
[509]1963       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1964       int sizeField = enabledFields.size();
1965       for (int numField = 0; numField < sizeField; ++numField)
1966       {
1967         if (0 != enabledFields[numField]->getRelGrid())
1968           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1969       }
1970     }
1971
1972     // Create all reference grids on server side
1973     StdString gridDefRoot("grid_definition");
1974     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1975     std::set<StdString>::const_iterator it, itE = gridIds.end();
1976     for (it = gridIds.begin(); it != itE; ++it)
1977     {
1978       gridPtr->sendCreateChild(*it);
1979       CGrid::get(*it)->sendAllAttributesToServer();
[540]1980       CGrid::get(*it)->sendAllDomains();
1981       CGrid::get(*it)->sendAllAxis();
[887]1982       CGrid::get(*it)->sendAllScalars();
[509]1983     }
1984   }
[1622]1985   CATCH_DUMP_ATTR
[509]1986
[1232]1987   //! Client side: Send information of reference domain, axis and scalar of active fields
1988   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
[1622]1989   TRY
[569]1990   {
[887]1991     std::set<StdString> domainIds, axisIds, scalarIds;
[509]1992
[569]1993     // Find all reference domain and axis of all active fields
[1232]1994     int numEnabledFiles = activeFiles.size();
[569]1995     for (int i = 0; i < numEnabledFiles; ++i)
1996     {
[1232]1997       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
[569]1998       int numEnabledFields = enabledFields.size();
1999       for (int j = 0; j < numEnabledFields; ++j)
2000       {
[887]2001         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
2002         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
2003         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
2004         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
[569]2005       }
2006     }
2007
2008     // Create all reference axis on server side
[887]2009     std::set<StdString>::iterator itDom, itAxis, itScalar;
[569]2010     std::set<StdString>::const_iterator itE;
2011
[887]2012     StdString scalarDefRoot("scalar_definition");
2013     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
2014     itE = scalarIds.end();
2015     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
2016     {
2017       if (!itScalar->empty())
2018       {
2019         scalarPtr->sendCreateChild(*itScalar);
2020         CScalar::get(*itScalar)->sendAllAttributesToServer();
2021       }
2022     }
2023
[569]2024     StdString axiDefRoot("axis_definition");
2025     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
2026     itE = axisIds.end();
2027     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
2028     {
2029       if (!itAxis->empty())
2030       {
2031         axisPtr->sendCreateChild(*itAxis);
2032         CAxis::get(*itAxis)->sendAllAttributesToServer();
2033       }
2034     }
2035
2036     // Create all reference domains on server side
2037     StdString domDefRoot("domain_definition");
2038     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
2039     itE = domainIds.end();
2040     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
2041     {
2042       if (!itDom->empty()) {
2043          domPtr->sendCreateChild(*itDom);
2044          CDomain::get(*itDom)->sendAllAttributesToServer();
2045       }
2046     }
2047   }
[1622]2048   CATCH_DUMP_ATTR
[569]2049
[509]2050   //! Update calendar in each time step
[300]2051   void CContext::updateCalendar(int step)
[1622]2052   TRY
[300]2053   {
[1357]2054      int prevStep = calendar->getStep();
2055
2056      if (prevStep < step)
[639]2057      {
[1358]2058        if (hasClient && !hasServer) // For now we only use server level 1 to read data
2059        {
2060          doPreTimestepOperationsForEnabledReadModeFiles();
2061        }
2062
[1357]2063        info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
2064        calendar->update(step);
2065        info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
2066  #ifdef XIOS_MEMTRACK_LIGHT
2067        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
2068  #endif
2069
2070        if (hasClient && !hasServer) // For now we only use server level 1 to read data
2071        {
2072          doPostTimestepOperationsForEnabledReadModeFiles();
2073          garbageCollector.invalidate(calendar->getCurrentDate());
2074        }
[639]2075      }
[1357]2076      else if (prevStep == step)
2077        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
2078      else // if (prevStep > step)
2079        ERROR("void CContext::updateCalendar(int step)",
2080              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
[300]2081   }
[1622]2082   CATCH_DUMP_ATTR
[509]2083
[1232]2084   void CContext::initReadFiles(void)
[1622]2085   TRY
[1232]2086   {
2087      vector<CFile*>::const_iterator it;
2088
2089      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
2090      {
2091         (*it)->initRead();
2092      }
2093   }
[1622]2094   CATCH_DUMP_ATTR
[1232]2095
[509]2096   //! Server side: Create header of netcdf file
[1232]2097   void CContext::createFileHeader(void)
[1622]2098   TRY
[300]2099   {
[549]2100      vector<CFile*>::const_iterator it;
[509]2101
[300]2102      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
[1232]2103      // for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
[300]2104      {
[1232]2105         (*it)->initWrite();
[300]2106      }
[509]2107   }
[1622]2108   CATCH_DUMP_ATTR
[509]2109
2110   //! Get current context
[347]2111   CContext* CContext::getCurrent(void)
[1622]2112   TRY
[300]2113   {
[549]2114     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
[300]2115   }
[1622]2116   CATCH
[509]2117
2118   /*!
2119   \brief Set context with an id be the current context
2120   \param [in] id identity of context to be set to current
2121   */
[346]2122   void CContext::setCurrent(const string& id)
[1622]2123   TRY
[346]2124   {
2125     CObjectFactory::SetCurrentContextId(id);
2126     CGroupFactory::SetCurrentContextId(id);
2127   }
[1622]2128   CATCH
[509]2129
2130  /*!
2131  \brief Create a context with specific id
2132  \param [in] id identity of new context
2133  \return pointer to the new context or already-existed one with identity id
2134  */
[347]2135  CContext* CContext::create(const StdString& id)
[1622]2136  TRY
[346]2137  {
[549]2138    CContext::setCurrent(id);
[509]2139
[346]2140    bool hasctxt = CContext::has(id);
[347]2141    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
[549]2142    getRoot();
[347]2143    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
[346]2144
2145#define DECLARE_NODE(Name_, name_) \
2146    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
2147#define DECLARE_NODE_PAR(Name_, name_)
2148#include "node_type.conf"
2149
2150    return (context);
2151  }
[1622]2152  CATCH
[697]2153
2154     //! Server side: Receive a message to do some post processing
2155  void CContext::recvRegistry(CEventServer& event)
[1622]2156  TRY
[697]2157  {
2158    CBufferIn* buffer=event.subEvents.begin()->buffer;
2159    string id;
2160    *buffer>>id;
2161    get(id)->recvRegistry(*buffer);
2162  }
[1622]2163  CATCH
[697]2164
2165  void CContext::recvRegistry(CBufferIn& buffer)
[1622]2166  TRY
[697]2167  {
2168    if (server->intraCommRank==0)
2169    {
2170      CRegistry registry(server->intraComm) ;
2171      registry.fromBuffer(buffer) ;
2172      registryOut->mergeRegistry(registry) ;
2173    }
2174  }
[1622]2175  CATCH_DUMP_ATTR
[697]2176
2177  void CContext::sendRegistry(void)
[1622]2178  TRY
[1158]2179  {
[697]2180    registryOut->hierarchicalGatherRegistry() ;
2181
[1009]2182    // Use correct context client to send message
[1030]2183    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]2184    for (int i = 0; i < nbSrvPools; ++i)
2185    {
2186      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
2187      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
[1021]2188        if (contextClientTmp->isServerLeader())
[1009]2189        {
2190           CMessage msg ;
2191           if (hasServer)
2192             msg<<this->getIdServer(i);
2193           else
2194             msg<<this->getIdServer();
2195           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
[1021]2196           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
[1009]2197           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2198             event.push(*itRank,1,msg);
2199           contextClientTmp->sendEvent(event);
2200         }
2201         else contextClientTmp->sendEvent(event);
2202    }
[697]2203  }
[1622]2204  CATCH_DUMP_ATTR
[697]2205
[1764]2206 
2207  void CContext::sendFinalizeClient(CContextClient* contextClient, const string& contextClientId)
2208  TRY
2209  {
2210    CEventClient event(getType(),EVENT_ID_CONTEXT_FINALIZE_CLIENT);
2211    if (contextClient->isServerLeader())
2212    {
2213      CMessage msg;
2214      msg<<contextClientId ;
2215      const std::list<int>& ranks = contextClient->getRanksServerLeader();
2216      for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2217           event.push(*itRank,1,msg);
2218      contextClient->sendEvent(event);
2219    }
2220    else contextClient->sendEvent(event);
2221  }
2222  CATCH_DUMP_ATTR
2223
2224 
2225  void CContext::recvFinalizeClient(CEventServer& event)
2226  TRY
2227  {
2228    CBufferIn* buffer=event.subEvents.begin()->buffer;
2229    string id;
2230    *buffer>>id;
2231    get(id)->recvFinalizeClient(*buffer);
2232  }
2233  CATCH
2234
2235  void CContext::recvFinalizeClient(CBufferIn& buffer)
2236  TRY
2237  {
2238    countChildContextFinalized_++ ;
2239  }
2240  CATCH_DUMP_ATTR
2241
2242
2243
2244
[1130]2245  /*!
2246  * \fn bool CContext::isFinalized(void)
[1139]2247  * Context is finalized if it received context post finalize event.
[1130]2248  */
[1054]2249  bool CContext::isFinalized(void)
[1622]2250  TRY
[1054]2251  {
[1139]2252    return finalized;
[1054]2253  }
[1622]2254  CATCH_DUMP_ATTR
2255  ///--------------------------------------------------------------
2256  StdString CContext::dumpClassAttributes(void)
2257  {
2258    StdString str;
2259    str.append("enabled files=\"");
2260    int size = this->enabledFiles.size();
2261    for (int i = 0; i < size; ++i)
2262    {
2263      str.append(enabledFiles[i]->getId());
2264      str.append(" ");
2265    }
2266    str.append("\"");
2267    return str;
2268  }
[1054]2269
[335]2270} // namespace xios
Note: See TracBrowser for help on using the repository browser.