source: XIOS/dev/branch_openmp/src/node/context.cpp @ 1460

Last change on this file since 1460 was 1460, checked in by yushan, 6 years ago

branch_openmp merged with XIOS_DEV_CMIP6@1459

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