source: XIOS/trunk/src/node/context.cpp @ 1137

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

Add "light" memory tracking which must be activated at compile time : make_xios --memtrack light

  • report at info level 10 : max memory consumption and the current memory consumption at the end of exection
  • info at info level 50 : at each timestep, the current memory consumption is printed

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: 43.4 KB
Line 
1#include "context.hpp"
2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
5
6#include "calendar_type.hpp"
7#include "duration.hpp"
8
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "nc4_data_output.hpp"
12#include "node_type.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "timer.hpp"
17#include "memtrack.hpp"
18
19
20namespace xios {
21
22  shared_ptr<CContextGroup> CContext::root;
23
24   /// ////////////////////// Définitions ////////////////////// ///
25
26   CContext::CContext(void)
27      : CObjectTemplate<CContext>(), CContextAttributes()
28      , calendar(), hasClient(false), hasServer(false), isPostProcessed(false), finalized(false)
29      , idServer_(), client(0), server(0)
30   { /* Ne rien faire de plus */ }
31
32   CContext::CContext(const StdString & id)
33      : CObjectTemplate<CContext>(id), CContextAttributes()
34      , calendar(), hasClient(false), hasServer(false), isPostProcessed(false), finalized(false)
35      , idServer_(), client(0), server(0)
36   { /* Ne rien faire de plus */ }
37
38   CContext::~CContext(void)
39   {
40     delete client;
41     delete server;
42   }
43
44   //----------------------------------------------------------------
45   //! Get name of context
46   StdString CContext::GetName(void)   { return (StdString("context")); }
47   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
48   ENodeType CContext::GetType(void)   { return (eContext); }
49
50   //----------------------------------------------------------------
51
52   /*!
53   \brief Get context group (context root)
54   \return Context root
55   */
56   CContextGroup* CContext::getRoot(void)
57   {
58      if (root.get()==NULL) root=shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
59      return root.get();
60   }
61
62   //----------------------------------------------------------------
63
64   /*!
65   \brief Get calendar of a context
66   \return Calendar
67   */
68   boost::shared_ptr<CCalendar> CContext::getCalendar(void) const
69   {
70      return (this->calendar);
71   }
72
73   //----------------------------------------------------------------
74
75   /*!
76   \brief Set a context with a calendar
77   \param[in] newCalendar new calendar
78   */
79   void CContext::setCalendar(boost::shared_ptr<CCalendar> newCalendar)
80   {
81      this->calendar = newCalendar;
82   }
83
84   //----------------------------------------------------------------
85   /*!
86   \brief Parse xml file and write information into context object
87   \param [in] node xmld node corresponding in xml file
88   */
89   void CContext::parse(xml::CXMLNode & node)
90   {
91      CContext::SuperClass::parse(node);
92
93      // PARSING POUR GESTION DES ENFANTS
94      xml::THashAttributes attributes = node.getAttributes();
95
96      if (attributes.end() != attributes.find("src"))
97      {
98         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
99         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
100            ERROR("void CContext::parse(xml::CXMLNode & node)",
101                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
102         if (!ifs.good())
103            ERROR("CContext::parse(xml::CXMLNode & node)",
104                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
105         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
106      }
107
108      if (node.getElementName().compare(CContext::GetName()))
109         DEBUG("Le noeud is wrong defined but will be considered as a context !");
110
111      if (!(node.goToChildElement()))
112      {
113         DEBUG("Le context ne contient pas d'enfant !");
114      }
115      else
116      {
117         do { // Parcours des contextes pour traitement.
118
119            StdString name = node.getElementName();
120            attributes.clear();
121            attributes = node.getAttributes();
122
123            if (attributes.end() != attributes.find("id"))
124            {
125              DEBUG(<< "Definition node has an id,"
126                    << "it will not be taking account !");
127            }
128
129#define DECLARE_NODE(Name_, name_)    \
130   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
131   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
132#define DECLARE_NODE_PAR(Name_, name_)
133#include "node_type.conf"
134
135            DEBUG(<< "The element \'"     << name
136                  << "\' in the context \'" << CContext::getCurrent()->getId()
137                  << "\' is not a definition !");
138
139         } while (node.goToNextElement());
140
141         node.goToParentElement(); // Retour au parent
142      }
143   }
144
145   //----------------------------------------------------------------
146   //! Show tree structure of context
147   void CContext::ShowTree(StdOStream & out)
148   {
149      StdString currentContextId = CContext::getCurrent() -> getId();
150      std::vector<CContext*> def_vector =
151         CContext::getRoot()->getChildList();
152      std::vector<CContext*>::iterator
153         it = def_vector.begin(), end = def_vector.end();
154
155      out << "<? xml version=\"1.0\" ?>" << std::endl;
156      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
157
158      for (; it != end; it++)
159      {
160         CContext* context = *it;
161         CContext::setCurrent(context->getId());
162         out << *context << std::endl;
163      }
164
165      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
166      CContext::setCurrent(currentContextId);
167   }
168
169
170   //----------------------------------------------------------------
171
172   //! Convert context object into string (to print)
173   StdString CContext::toString(void) const
174   {
175      StdOStringStream oss;
176      oss << "<" << CContext::GetName()
177          << " id=\"" << this->getId() << "\" "
178          << SuperClassAttribute::toString() << ">" << std::endl;
179      if (!this->hasChild())
180      {
181         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
182      }
183      else
184      {
185
186#define DECLARE_NODE(Name_, name_)    \
187   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
188   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
189#define DECLARE_NODE_PAR(Name_, name_)
190#include "node_type.conf"
191
192      }
193
194      oss << "</" << CContext::GetName() << " >";
195
196      return (oss.str());
197   }
198
199   //----------------------------------------------------------------
200
201   /*!
202   \brief Find all inheritace among objects in a context.
203   \param [in] apply (true) write attributes of parent into ones of child if they are empty
204                     (false) write attributes of parent into a new container of child
205   \param [in] parent unused
206   */
207   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
208   {
209#define DECLARE_NODE(Name_, name_)    \
210   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
211     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
212#define DECLARE_NODE_PAR(Name_, name_)
213#include "node_type.conf"
214   }
215
216   //----------------------------------------------------------------
217
218   //! Verify if all root definition in the context have child.
219   bool CContext::hasChild(void) const
220   {
221      return (
222#define DECLARE_NODE(Name_, name_)    \
223   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
224#define DECLARE_NODE_PAR(Name_, name_)
225#include "node_type.conf"
226      false);
227}
228
229   //----------------------------------------------------------------
230
231   void CContext::CleanTree(void)
232   {
233#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
234#define DECLARE_NODE_PAR(Name_, name_)
235#include "node_type.conf"
236   }
237   ///---------------------------------------------------------------
238
239   //! Initialize client side
240   void CContext::initClient(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtServer /*= 0*/)
241   {
242     hasClient=true;
243     client = new CContextClient(this,intraComm, interComm, cxtServer);
244     registryIn=new CRegistry(intraComm);
245     registryIn->setPath(getId()) ;
246     if (client->clientRank==0) registryIn->fromFile("xios_registry.bin") ;
247     registryIn->bcastRegistry() ;
248
249     registryOut=new CRegistry(intraComm) ;
250     registryOut->setPath(getId()) ;
251
252     MPI_Comm intraCommServer, interCommServer;
253     if (cxtServer) // Attached mode
254     {
255       intraCommServer = intraComm;
256       interCommServer = interComm;
257     }
258     else
259     {
260       MPI_Comm_dup(intraComm, &intraCommServer);
261       comms.push_back(intraCommServer);
262       MPI_Comm_dup(interComm, &interCommServer);
263       comms.push_back(interCommServer);
264     }
265     server = new CContextServer(this,intraCommServer,interCommServer);
266   }
267
268   void CContext::setClientServerBuffer()
269   {
270     size_t minBufferSize = CXios::minBufferSize;
271#define DECLARE_NODE(Name_, name_)    \
272     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
273#define DECLARE_NODE_PAR(Name_, name_)
274#include "node_type.conf"
275#undef DECLARE_NODE
276#undef DECLARE_NODE_PAR
277
278     std::map<int, StdSize> maxEventSize;
279     std::map<int, StdSize> bufferSize = getAttributesBufferSize(maxEventSize);
280     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize);
281
282     std::map<int, StdSize>::iterator it, ite = dataBufferSize.end();
283     for (it = dataBufferSize.begin(); it != ite; ++it)
284       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
285
286     ite = bufferSize.end();
287     for (it = bufferSize.begin(); it != ite; ++it)
288     {
289       it->second *= CXios::bufferSizeFactor;
290       if (it->second < minBufferSize) it->second = minBufferSize;
291     }
292
293     // We consider that the minimum buffer size is also the minimum event size
294     ite = maxEventSize.end();
295     for (it = maxEventSize.begin(); it != ite; ++it)
296       if (it->second < minBufferSize) it->second = minBufferSize;
297
298     if (client->isServerLeader())
299     {
300       const std::list<int>& ranks = client->getRanksServerLeader();
301       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
302         if (!bufferSize.count(*itRank)) bufferSize[*itRank] = maxEventSize[*itRank] = minBufferSize;
303     }
304
305     client->setBufferSize(bufferSize, maxEventSize);
306   }
307
308   //! Verify whether a context is initialized
309   bool CContext::isInitialized(void)
310   {
311     return hasClient;
312   }
313
314   //! Initialize server
315   void CContext::initServer(MPI_Comm intraComm,MPI_Comm interComm, CContext* cxtClient /*= 0*/)
316   {
317     hasServer=true;
318     server = new CContextServer(this,intraComm,interComm);
319
320     registryIn=new CRegistry(intraComm);
321     registryIn->setPath(getId()) ;
322     if (server->intraCommRank==0) registryIn->fromFile("xios_registry.bin") ;
323     registryIn->bcastRegistry() ;
324     registryOut=new CRegistry(intraComm) ;
325     registryOut->setPath(getId()) ;
326
327     MPI_Comm intraCommClient, interCommClient;
328     if (cxtClient) // Attached mode
329     {
330       intraCommClient = intraComm;
331       interCommClient = interComm;
332     }
333     else
334     {
335       MPI_Comm_dup(intraComm, &intraCommClient);
336       comms.push_back(intraCommClient);
337       MPI_Comm_dup(interComm, &interCommClient);
338       comms.push_back(interCommClient);
339     }
340     client = new CContextClient(this,intraCommClient,interCommClient, cxtClient);
341   }
342
343   //! Try to send the buffers and receive possible answers
344   bool CContext::checkBuffersAndListen(void)
345   {
346     client->checkBuffers();
347
348     bool hasTmpBufferedEvent = client->hasTemporarilyBufferedEvent();
349     if (hasTmpBufferedEvent)
350       hasTmpBufferedEvent = !client->sendTemporarilyBufferedEvent();
351
352     // Don't process events if there is a temporarily buffered event
353     return server->eventLoop(!hasTmpBufferedEvent);
354   }
355
356   //! Terminate a context
357   void CContext::finalize(void)
358   {
359      if (!finalized)
360      {
361        finalized = true;
362        if (hasClient) sendRegistry() ;
363        client->finalize();
364        while (!server->hasFinished())
365        {
366          server->eventLoop();
367        }
368
369        if (hasServer)
370        {
371          closeAllFile();
372          registryOut->hierarchicalGatherRegistry() ;
373          if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
374        }
375
376        for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
377          MPI_Comm_free(&(*it));
378        comms.clear();
379      }
380   }
381
382   /*!
383   \brief Close all the context defintion and do processing data
384      After everything is well defined on client side, they will be processed and sent to server
385   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
386   all necessary information to server, from which each server can build its own database.
387   Because the role of server is to write out field data on a specific netcdf file,
388   the only information that it needs is the enabled files
389   and the active fields (fields will be written onto active files)
390   */
391   void CContext::closeDefinition(void)
392   {
393     CTimer::get("Context : close definition").resume() ;
394     // There is nothing client need to send to server
395     if (hasClient)
396     {
397       // After xml is parsed, there are some more works with post processing
398       postProcessing();
399     }
400     setClientServerBuffer();
401
402     if (hasClient && !hasServer)
403     {
404      // Send all attributes of current context to server
405      this->sendAllAttributesToServer();
406
407      // Send all attributes of current calendar
408      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
409
410      // We have enough information to send to server
411      // First of all, send all enabled files
412       sendEnabledFiles();
413
414      // Then, send all enabled fields
415       sendEnabledFields();
416
417      // At last, we have all info of domain and axis, then send them
418       sendRefDomainsAxis();
419
420      // After that, send all grid (if any)
421       sendRefGrid();
422    }
423
424    // We have a xml tree on the server side and now, it should be also processed
425    if (hasClient && !hasServer) sendPostProcessing();
426
427    // There are some processings that should be done after all of above. For example: check mask or index
428    if (hasClient)
429    {
430      this->buildFilterGraphOfEnabledFields();
431      buildFilterGraphOfFieldsWithReadAccess();
432      this->solveAllRefOfEnabledFields(true);
433    }
434
435    // Now tell server that it can process all messages from client
436    if (hasClient && !hasServer) this->sendCloseDefinition();
437
438    // Nettoyage de l'arborescence
439    if (hasClient && !hasServer) CleanTree(); // Only on client side??
440
441    if (hasClient)
442    {
443      sendCreateFileHeader();
444
445      startPrefetchingOfEnabledReadModeFiles();
446    }
447    CTimer::get("Context : close definition").suspend() ;
448   }
449
450   void CContext::findAllEnabledFields(void)
451   {
452     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
453     (void)this->enabledFiles[i]->getEnabledFields();
454   }
455
456   void CContext::findAllEnabledFieldsInReadModeFiles(void)
457   {
458     for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
459     (void)this->enabledReadModeFiles[i]->getEnabledFields();
460   }
461
462   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
463   {
464      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
465        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
466   }
467
468   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
469   {
470     int size = this->enabledFiles.size();
471     for (int i = 0; i < size; ++i)
472     {
473       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
474     }
475
476     for (int i = 0; i < size; ++i)
477     {
478       this->enabledFiles[i]->generateNewTransformationGridDest();
479     }
480   }
481
482   void CContext::solveAllRefOfEnabledFields(bool sendToServer)
483   {
484     int size = this->enabledFiles.size();
485     for (int i = 0; i < size; ++i)
486     {
487       this->enabledFiles[i]->solveAllRefOfEnabledFields(sendToServer);
488     }
489   }
490
491   void CContext::buildFilterGraphOfEnabledFields()
492   {
493     int size = this->enabledFiles.size();
494     for (int i = 0; i < size; ++i)
495     {
496       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
497     }
498   }
499
500   void CContext::startPrefetchingOfEnabledReadModeFiles()
501   {
502     int size = enabledReadModeFiles.size();
503     for (int i = 0; i < size; ++i)
504     {
505        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
506     }
507   }
508
509   void CContext::checkPrefetchingOfEnabledReadModeFiles()
510   {
511     int size = enabledReadModeFiles.size();
512     for (int i = 0; i < size; ++i)
513     {
514        enabledReadModeFiles[i]->prefetchEnabledReadModeFieldsIfNeeded();
515     }
516   }
517
518  void CContext::findFieldsWithReadAccess(void)
519  {
520    fieldsWithReadAccess.clear();
521    const vector<CField*> allFields = CField::getAll();
522    for (size_t i = 0; i < allFields.size(); ++i)
523    {
524      CField* field = allFields[i];
525
526      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
527        field->read_access = true;
528      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
529        fieldsWithReadAccess.push_back(field);
530    }
531  }
532
533  void CContext::solveAllRefOfFieldsWithReadAccess()
534  {
535    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
536      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
537  }
538
539  void CContext::buildFilterGraphOfFieldsWithReadAccess()
540  {
541    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
542      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
543  }
544
545   void CContext::solveAllInheritance(bool apply)
546   {
547     // Résolution des héritages descendants (càd des héritages de groupes)
548     // pour chacun des contextes.
549      solveDescInheritance(apply);
550
551     // Résolution des héritages par référence au niveau des fichiers.
552      const vector<CFile*> allFiles=CFile::getAll();
553      const vector<CGrid*> allGrids= CGrid::getAll();
554
555     //if (hasClient && !hasServer)
556      if (hasClient)
557      {
558        for (unsigned int i = 0; i < allFiles.size(); i++)
559          allFiles[i]->solveFieldRefInheritance(apply);
560      }
561
562      unsigned int vecSize = allGrids.size();
563      unsigned int i = 0;
564      for (i = 0; i < vecSize; ++i)
565        allGrids[i]->solveDomainAxisRefInheritance(apply);
566
567   }
568
569   void CContext::findEnabledFiles(void)
570   {
571      const std::vector<CFile*> allFiles = CFile::getAll();
572      const CDate& initDate = calendar->getInitDate();
573
574      for (unsigned int i = 0; i < allFiles.size(); i++)
575         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
576         {
577            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
578            {
579              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
580              {
581                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
582                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
583                    <<"\" is less than the time step. File will not be written."<<endl;
584              }
585              else
586               enabledFiles.push_back(allFiles[i]);
587            }
588         }
589         else
590         {
591           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
592           {
593             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
594                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
595                 <<"\" is less than the time step. File will not be written."<<endl;
596           }
597           else
598             enabledFiles.push_back(allFiles[i]); // otherwise true by default
599         }
600
601      if (enabledFiles.size() == 0)
602         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
603               << getId() << "\" !");
604   }
605
606   void CContext::findEnabledReadModeFiles(void)
607   {
608     int size = this->enabledFiles.size();
609     for (int i = 0; i < size; ++i)
610     {
611       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
612        enabledReadModeFiles.push_back(enabledFiles[i]);
613     }
614   }
615
616   void CContext::closeAllFile(void)
617   {
618     std::vector<CFile*>::const_iterator
619            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
620
621     for (; it != end; it++)
622     {
623       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
624       (*it)->close();
625     }
626   }
627
628   /*!
629   \brief Dispatch event received from client
630      Whenever a message is received in buffer of server, it will be processed depending on
631   its event type. A new event type should be added in the switch list to make sure
632   it processed on server side.
633   \param [in] event: Received message
634   */
635   bool CContext::dispatchEvent(CEventServer& event)
636   {
637
638      if (SuperClass::dispatchEvent(event)) return true;
639      else
640      {
641        switch(event.type)
642        {
643           case EVENT_ID_CLOSE_DEFINITION :
644             recvCloseDefinition(event);
645             return true;
646             break;
647           case EVENT_ID_UPDATE_CALENDAR:
648             recvUpdateCalendar(event);
649             return true;
650             break;
651           case EVENT_ID_CREATE_FILE_HEADER :
652             recvCreateFileHeader(event);
653             return true;
654             break;
655           case EVENT_ID_POST_PROCESS:
656             recvPostProcessing(event);
657             return true;
658            case EVENT_ID_SEND_REGISTRY:
659             recvRegistry(event);
660             return true;
661            break;
662
663           default :
664             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
665                    <<"Unknown Event");
666           return false;
667         }
668      }
669   }
670
671   //! Client side: Send a message to server to make it close
672   void CContext::sendCloseDefinition(void)
673   {
674     CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
675     if (client->isServerLeader())
676     {
677       CMessage msg;
678       msg<<this->getIdServer();
679       const std::list<int>& ranks = client->getRanksServerLeader();
680       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
681         event.push(*itRank,1,msg);
682       client->sendEvent(event);
683     }
684     else client->sendEvent(event);
685   }
686
687   //! Server side: Receive a message of client announcing a context close
688   void CContext::recvCloseDefinition(CEventServer& event)
689   {
690
691      CBufferIn* buffer=event.subEvents.begin()->buffer;
692      string id;
693      *buffer>>id;
694      get(id)->closeDefinition();
695   }
696
697   //! Client side: Send a message to update calendar in each time step
698   void CContext::sendUpdateCalendar(int step)
699   {
700     if (!hasServer)
701     {
702       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
703       if (client->isServerLeader())
704       {
705         CMessage msg;
706         msg<<this->getIdServer()<<step;
707         const std::list<int>& ranks = client->getRanksServerLeader();
708         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
709           event.push(*itRank,1,msg);
710         client->sendEvent(event);
711       }
712       else client->sendEvent(event);
713     }
714   }
715
716   //! Server side: Receive a message of client annoucing calendar update
717   void CContext::recvUpdateCalendar(CEventServer& event)
718   {
719      CBufferIn* buffer=event.subEvents.begin()->buffer;
720      string id;
721      *buffer>>id;
722      get(id)->recvUpdateCalendar(*buffer);
723   }
724
725   //! Server side: Receive a message of client annoucing calendar update
726   void CContext::recvUpdateCalendar(CBufferIn& buffer)
727   {
728      int step;
729      buffer>>step;
730      updateCalendar(step);
731   }
732
733   //! Client side: Send a message to create header part of netcdf file
734   void CContext::sendCreateFileHeader(void)
735   {
736     CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
737     if (client->isServerLeader())
738     {
739       CMessage msg;
740       msg<<this->getIdServer();
741       const std::list<int>& ranks = client->getRanksServerLeader();
742       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
743         event.push(*itRank,1,msg) ;
744       client->sendEvent(event);
745     }
746     else client->sendEvent(event);
747   }
748
749   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
750   void CContext::recvCreateFileHeader(CEventServer& event)
751   {
752      CBufferIn* buffer=event.subEvents.begin()->buffer;
753      string id;
754      *buffer>>id;
755      get(id)->recvCreateFileHeader(*buffer);
756   }
757
758   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
759   void CContext::recvCreateFileHeader(CBufferIn& buffer)
760   {
761      createFileHeader();
762   }
763
764   //! Client side: Send a message to do some post processing on server
765   void CContext::sendPostProcessing()
766   {
767     if (!hasServer)
768     {
769       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
770       if (client->isServerLeader())
771       {
772         CMessage msg;
773         msg<<this->getIdServer();
774         const std::list<int>& ranks = client->getRanksServerLeader();
775         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
776           event.push(*itRank,1,msg);
777         client->sendEvent(event);
778       }
779       else client->sendEvent(event);
780     }
781   }
782
783   //! Server side: Receive a message to do some post processing
784   void CContext::recvPostProcessing(CEventServer& event)
785   {
786      CBufferIn* buffer=event.subEvents.begin()->buffer;
787      string id;
788      *buffer>>id;
789      get(id)->recvPostProcessing(*buffer);
790   }
791
792   //! Server side: Receive a message to do some post processing
793   void CContext::recvPostProcessing(CBufferIn& buffer)
794   {
795      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
796      postProcessing();
797   }
798
799   const StdString& CContext::getIdServer()
800   {
801      if (hasClient)
802      {
803        idServer_ = this->getId();
804        idServer_ += "_server";
805        return idServer_;
806      }
807      if (hasServer) return (this->getId());
808   }
809
810   /*!
811   \brief Do some simple post processings after parsing xml file
812      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
813   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
814   which will be written out into netcdf files, are processed
815   */
816   void CContext::postProcessing()
817   {
818     if (isPostProcessed) return;
819
820      // Make sure the calendar was correctly created
821      if (!calendar)
822        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
823      else if (calendar->getTimeStep() == NoneDu)
824        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
825      // Calendar first update to set the current date equals to the start date
826      calendar->update(0);
827
828      // Find all inheritance in xml structure
829      this->solveAllInheritance();
830
831      // Check if some axis, domains or grids are eligible to for compressed indexed output.
832      // Warning: This must be done after solving the inheritance and before the rest of post-processing
833      checkAxisDomainsGridsEligibilityForCompressedOutput();
834
835      // Check if some automatic time series should be generated
836      // Warning: This must be done after solving the inheritance and before the rest of post-processing
837      prepareTimeseries();
838
839      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
840      this->findEnabledFiles();
841      this->findEnabledReadModeFiles();
842
843      // Find all enabled fields of each file
844      this->findAllEnabledFields();
845      this->findAllEnabledFieldsInReadModeFiles();
846
847     if (hasClient && !hasServer)
848     {
849      // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
850      this->readAttributesOfEnabledFieldsInReadModeFiles();
851     }
852
853      // Only search and rebuild all reference objects of enable fields, don't transform
854      this->solveOnlyRefOfEnabledFields(false);
855
856      // Search and rebuild all reference object of enabled fields
857      this->solveAllRefOfEnabledFields(false);
858
859      // Find all fields with read access from the public API
860      findFieldsWithReadAccess();
861      // and solve the all reference for them
862      solveAllRefOfFieldsWithReadAccess();
863
864      isPostProcessed = true;
865   }
866
867   /*!
868    * Compute the required buffer size to send the attributes (mostly those grid related).
869    *
870    * \param maxEventSize [in/out] the size of the bigger event for each connected server
871    */
872   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize)
873   {
874     std::map<int, StdSize> attributesSize;
875
876     if (hasClient)
877     {
878       size_t numEnabledFiles = this->enabledFiles.size();
879       for (size_t i = 0; i < numEnabledFiles; ++i)
880       {
881         CFile* file = this->enabledFiles[i];
882
883         std::vector<CField*> enabledFields = file->getEnabledFields();
884         size_t numEnabledFields = enabledFields.size();
885         for (size_t j = 0; j < numEnabledFields; ++j)
886         {
887           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize();
888           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
889           for (; it != itE; ++it)
890           {
891             // If attributesSize[it->first] does not exist, it will be zero-initialized
892             // so we can use it safely without checking for its existance
893             if (attributesSize[it->first] < it->second)
894               attributesSize[it->first] = it->second;
895
896             if (maxEventSize[it->first] < it->second)
897               maxEventSize[it->first] = it->second;
898           }
899         }
900       }
901     }
902
903     return attributesSize;
904   }
905
906   /*!
907    * Compute the required buffer size to send the fields data.
908    *
909    * \param maxEventSize [in/out] the size of the bigger event for each connected server
910    */
911   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize)
912   {
913     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
914
915     std::map<int, StdSize> dataSize;
916
917     // Find all reference domain and axis of all active fields
918     size_t numEnabledFiles = this->enabledFiles.size();
919     for (size_t i = 0; i < numEnabledFiles; ++i)
920     {
921       CFile* file = this->enabledFiles[i];
922       CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
923
924       if (fileMode == mode)
925       {
926         std::vector<CField*> enabledFields = file->getEnabledFields();
927         size_t numEnabledFields = enabledFields.size();
928         for (size_t j = 0; j < numEnabledFields; ++j)
929         {
930           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize();
931           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
932           for (; it != itE; ++it)
933           {
934             // If dataSize[it->first] does not exist, it will be zero-initialized
935             // so we can use it safely without checking for its existance
936             if (CXios::isOptPerformance)
937               dataSize[it->first] += it->second;
938             else if (dataSize[it->first] < it->second)
939               dataSize[it->first] = it->second;
940
941             if (maxEventSize[it->first] < it->second)
942               maxEventSize[it->first] = it->second;
943           }
944         }
945       }
946     }
947
948     return dataSize;
949   }
950
951   //! Client side: Send infomation of active files (files are enabled to write out)
952   void CContext::sendEnabledFiles()
953   {
954     int size = this->enabledFiles.size();
955
956     // In a context, each type has a root definition, e.g: axis, domain, field.
957     // Every object must be a child of one of these root definition. In this case
958     // all new file objects created on server must be children of the root "file_definition"
959     StdString fileDefRoot("file_definition");
960     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
961
962     for (int i = 0; i < size; ++i)
963     {
964       cfgrpPtr->sendCreateChild(this->enabledFiles[i]->getId());
965       this->enabledFiles[i]->sendAllAttributesToServer();
966       this->enabledFiles[i]->sendAddAllVariables();
967     }
968   }
969
970   //! Client side: Send information of active fields (ones are written onto files)
971   void CContext::sendEnabledFields()
972   {
973     int size = this->enabledFiles.size();
974     for (int i = 0; i < size; ++i)
975     {
976       this->enabledFiles[i]->sendEnabledFields();
977     }
978   }
979
980   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
981   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
982   {
983     if (!hasClient) return;
984
985     const vector<CAxis*> allAxis = CAxis::getAll();
986     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
987       (*it)->checkEligibilityForCompressedOutput();
988
989     const vector<CDomain*> allDomains = CDomain::getAll();
990     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
991       (*it)->checkEligibilityForCompressedOutput();
992
993     const vector<CGrid*> allGrids = CGrid::getAll();
994     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
995       (*it)->checkEligibilityForCompressedOutput();
996   }
997
998   //! Client side: Prepare the timeseries by adding the necessary files
999   void CContext::prepareTimeseries()
1000   {
1001     if (!hasClient) return;
1002
1003     const std::vector<CFile*> allFiles = CFile::getAll();
1004     for (size_t i = 0; i < allFiles.size(); i++)
1005     {
1006       CFile* file = allFiles[i];
1007
1008       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1009       for (size_t k = 0; k < vars.size(); k++)
1010       {
1011         CVariable* var = vars[k];
1012
1013         if (var->ts_target.isEmpty()
1014              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1015           fileVars.push_back(var);
1016
1017         if (!var->ts_target.isEmpty()
1018              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1019           fieldVars.push_back(var);
1020       }
1021
1022       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1023       {
1024         StdString fileNameStr("%file_name%") ;
1025         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1026         
1027         StdString fileName=file->getFileOutputName();
1028         size_t pos=tsPrefix.find(fileNameStr) ;
1029         while (pos!=std::string::npos)
1030         {
1031           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1032           pos=tsPrefix.find(fileNameStr) ;
1033         }
1034       
1035         const std::vector<CField*> allFields = file->getAllFields();
1036         for (size_t j = 0; j < allFields.size(); j++)
1037         {
1038           CField* field = allFields[j];
1039
1040           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1041           {
1042             CFile* tsFile = CFile::create();
1043             tsFile->duplicateAttributes(file);
1044
1045             // Add variables originating from file and targeted to timeserie file
1046             for (size_t k = 0; k < fileVars.size(); k++)
1047               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1048
1049           
1050             tsFile->name = tsPrefix + "_";
1051             if (!field->name.isEmpty())
1052               tsFile->name.get() += field->name;
1053             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1054               tsFile->name.get() += field->field_ref;
1055             else
1056               tsFile->name.get() += field->getId();
1057
1058             if (!field->ts_split_freq.isEmpty())
1059               tsFile->split_freq = field->ts_split_freq;
1060
1061             CField* tsField = tsFile->addField();
1062             tsField->field_ref = field->getId();
1063
1064             // Add variables originating from file and targeted to timeserie field
1065             for (size_t k = 0; k < fieldVars.size(); k++)
1066               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1067
1068             vars = field->getAllVariables();
1069             for (size_t k = 0; k < vars.size(); k++)
1070             {
1071               CVariable* var = vars[k];
1072
1073               // Add variables originating from field and targeted to timeserie field
1074               if (var->ts_target.isEmpty()
1075                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1076                 tsField->getVirtualVariableGroup()->addChild(var);
1077
1078               // Add variables originating from field and targeted to timeserie file
1079               if (!var->ts_target.isEmpty()
1080                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1081                 tsFile->getVirtualVariableGroup()->addChild(var);
1082             }
1083
1084             tsFile->solveFieldRefInheritance(true);
1085
1086             if (file->timeseries == CFile::timeseries_attr::exclusive)
1087               field->enabled = false;
1088           }
1089         }
1090
1091         // Finally disable the original file is need be
1092         if (file->timeseries == CFile::timeseries_attr::only)
1093          file->enabled = false;
1094       }
1095     }
1096   }
1097
1098   //! Client side: Send information of reference grid of active fields
1099   void CContext::sendRefGrid()
1100   {
1101     std::set<StdString> gridIds;
1102     int sizeFile = this->enabledFiles.size();
1103     CFile* filePtr(NULL);
1104
1105     // Firstly, find all reference grids of all active fields
1106     for (int i = 0; i < sizeFile; ++i)
1107     {
1108       filePtr = this->enabledFiles[i];
1109       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1110       int sizeField = enabledFields.size();
1111       for (int numField = 0; numField < sizeField; ++numField)
1112       {
1113         if (0 != enabledFields[numField]->getRelGrid())
1114           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1115       }
1116     }
1117
1118     // Create all reference grids on server side
1119     StdString gridDefRoot("grid_definition");
1120     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1121     std::set<StdString>::const_iterator it, itE = gridIds.end();
1122     for (it = gridIds.begin(); it != itE; ++it)
1123     {
1124       gridPtr->sendCreateChild(*it);
1125       CGrid::get(*it)->sendAllAttributesToServer();
1126       CGrid::get(*it)->sendAllDomains();
1127       CGrid::get(*it)->sendAllAxis();
1128       CGrid::get(*it)->sendAllScalars();
1129     }
1130   }
1131
1132
1133   //! Client side: Send information of reference domain and axis of active fields
1134   void CContext::sendRefDomainsAxis()
1135   {
1136     std::set<StdString> domainIds, axisIds, scalarIds;
1137
1138     // Find all reference domain and axis of all active fields
1139     int numEnabledFiles = this->enabledFiles.size();
1140     for (int i = 0; i < numEnabledFiles; ++i)
1141     {
1142       std::vector<CField*> enabledFields = this->enabledFiles[i]->getEnabledFields();
1143       int numEnabledFields = enabledFields.size();
1144       for (int j = 0; j < numEnabledFields; ++j)
1145       {
1146         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1147         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1148         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1149         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1150       }
1151     }
1152
1153     // Create all reference axis on server side
1154     std::set<StdString>::iterator itDom, itAxis, itScalar;
1155     std::set<StdString>::const_iterator itE;
1156
1157     StdString scalarDefRoot("scalar_definition");
1158     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1159     itE = scalarIds.end();
1160     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1161     {
1162       if (!itScalar->empty())
1163       {
1164         scalarPtr->sendCreateChild(*itScalar);
1165         CScalar::get(*itScalar)->sendAllAttributesToServer();
1166       }
1167     }
1168
1169     StdString axiDefRoot("axis_definition");
1170     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1171     itE = axisIds.end();
1172     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1173     {
1174       if (!itAxis->empty())
1175       {
1176         axisPtr->sendCreateChild(*itAxis);
1177         CAxis::get(*itAxis)->sendAllAttributesToServer();
1178       }
1179     }
1180
1181     // Create all reference domains on server side
1182     StdString domDefRoot("domain_definition");
1183     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1184     itE = domainIds.end();
1185     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1186     {
1187       if (!itDom->empty()) {
1188          domPtr->sendCreateChild(*itDom);
1189          CDomain::get(*itDom)->sendAllAttributesToServer();
1190       }
1191     }
1192   }
1193
1194   //! Update calendar in each time step
1195   void CContext::updateCalendar(int step)
1196   {
1197      info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1198      calendar->update(step);
1199      info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1200#ifdef XIOS_MEMTRACK_LIGHT
1201      info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1202#endif
1203      if (hasClient)
1204      {
1205        checkPrefetchingOfEnabledReadModeFiles();
1206        garbageCollector.invalidate(calendar->getCurrentDate());
1207      }
1208   }
1209
1210   //! Server side: Create header of netcdf file
1211   void CContext::createFileHeader(void )
1212   {
1213      vector<CFile*>::const_iterator it;
1214
1215      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1216      {
1217         (*it)->initFile();
1218      }
1219   }
1220
1221   //! Get current context
1222   CContext* CContext::getCurrent(void)
1223   {
1224     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1225   }
1226
1227   /*!
1228   \brief Set context with an id be the current context
1229   \param [in] id identity of context to be set to current
1230   */
1231   void CContext::setCurrent(const string& id)
1232   {
1233     CObjectFactory::SetCurrentContextId(id);
1234     CGroupFactory::SetCurrentContextId(id);
1235   }
1236
1237  /*!
1238  \brief Create a context with specific id
1239  \param [in] id identity of new context
1240  \return pointer to the new context or already-existed one with identity id
1241  */
1242  CContext* CContext::create(const StdString& id)
1243  {
1244    CContext::setCurrent(id);
1245
1246    bool hasctxt = CContext::has(id);
1247    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1248    getRoot();
1249    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1250
1251#define DECLARE_NODE(Name_, name_) \
1252    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1253#define DECLARE_NODE_PAR(Name_, name_)
1254#include "node_type.conf"
1255
1256    return (context);
1257  }
1258
1259
1260
1261     //! Server side: Receive a message to do some post processing
1262  void CContext::recvRegistry(CEventServer& event)
1263  {
1264    CBufferIn* buffer=event.subEvents.begin()->buffer;
1265    string id;
1266    *buffer>>id;
1267    get(id)->recvRegistry(*buffer);
1268  }
1269
1270  void CContext::recvRegistry(CBufferIn& buffer)
1271  {
1272    if (server->intraCommRank==0)
1273    {
1274      CRegistry registry(server->intraComm) ;
1275      registry.fromBuffer(buffer) ;
1276      registryOut->mergeRegistry(registry) ;
1277    }
1278  }
1279
1280  void CContext::sendRegistry(void)
1281  {
1282    registryOut->hierarchicalGatherRegistry() ;
1283
1284    CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1285    if (client->isServerLeader())
1286    {
1287       CMessage msg ;
1288       msg<<this->getIdServer();
1289       if (client->clientRank==0) msg<<*registryOut ;
1290       const std::list<int>& ranks = client->getRanksServerLeader();
1291       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1292         event.push(*itRank,1,msg);
1293       client->sendEvent(event);
1294     }
1295     else client->sendEvent(event);
1296  }
1297
1298} // namespace xios
Note: See TracBrowser for help on using the repository browser.