fpmas 1.6
grid.h
Go to the documentation of this file.
1#ifndef FPMAS_GRID_H
2#define FPMAS_GRID_H
3
10#include "fpmas/random/random.h"
11#include "spatial_model.h"
13
14namespace fpmas { namespace model {
15 using api::model::DiscretePoint;
17
22 struct PointHash {
38 std::size_t operator()(const DiscretePoint& p) const;
39 };
40
49 template<typename GridCellType, typename Derived = GridCellType>
51 public CellBase<api::model::GridCell, GridCellType, GridCellBase<GridCellType, Derived>> {
52 friend nlohmann::adl_serializer<fpmas::api::utils::PtrWrapper<GridCellBase<GridCellType, Derived>>>;
54
55 private:
56 DiscretePoint _location;
58
59 public:
64
69
76 : _location(location) {}
77
81 DiscretePoint location() const override {
82 return _location;
83 }
84
89 return _rd;
90 }
91
95 void seed(random::FPMAS_AGENT_RNG::result_type seed) override {
96 _rd.seed(seed);
97 }
98 };
99
104 class GridCell : public GridCellBase<GridCell> {
105 public:
107 };
108
119 template<typename AgentType, typename GridCellType = model::GridCell, typename Derived = AgentType>
120 class GridAgent :
121 public SpatialAgentBase<api::model::GridAgent<GridCellType>, AgentType, GridCellType, GridAgent<AgentType, GridCellType, Derived>> {
122 friend nlohmann::adl_serializer<api::utils::PtrWrapper<GridAgent<AgentType, GridCellType, Derived>>>;
124 static_assert(std::is_base_of<api::model::GridCell, GridCellType>::value,
125 "The specified GridCellType must extend api::model::GridCell.");
126
127 private:
129 DiscretePoint location_point {0, 0};
130
131 protected:
136 void moveTo(GridCellType* cell) override;
140 void moveTo(DiscretePoint point) override;
141
142 public:
146 DiscretePoint locationPoint() const override {return location_point;}
147
149 return _rd;
150 }
151
152 void seed(std::FPMAS_AGENT_RNG::result_type seed) override {
153 _rd.seed(seed);
154 }
155 };
156
157 template<typename AgentType, typename GridCellType, typename Derived>
159 this->updateLocation(cell);
160 location_point = cell->location();
161 }
162
163 template<typename AgentType, typename GridCellType, typename Derived>
165 bool found = false;
166 auto mobility_field = this->template outNeighbors<GridCellType>(SpatialModelLayers::MOVE);
167 auto it = mobility_field.begin();
168 while(!found && it != mobility_field.end()) {
169 if((*it)->location() == point) {
170 found=true;
171 } else {
172 it++;
173 }
174 }
175 if(found)
176 this->moveTo(*it);
177 else
178 throw api::model::OutOfMobilityFieldException(this->node()->getId(), this->locationPoint(), point);
179 }
180
187 template<typename GridCellType = GridCell>
189 public:
198 GridCellType* build(DiscretePoint location) override {
199 return new GridCellType(location);
200 }
201 };
202
210 template<>
212 api::model::GridCell* build(DiscretePoint location) override {
213 return new GridCell(location);
214 }
215 };
216
224
239
246 };
247
257 template<typename CellType = GridCell>
259 private:
260 // Count of items by DiscretePoint (no entry <=> 0)
261 std::map<DiscretePoint, std::size_t> item_counts;
262 GridAgentIndex agent_begin {&item_counts};
263 GridAgentIndex agent_end {&item_counts};
264 std::map<GridAgentIndex, api::model::GridAgent<CellType>*> agent_index;
265
266 public:
281 void build(
286 ) override;
287
292 void build(
295 std::function<api::model::SpatialAgent<CellType>*()> factory,
297 ) override;
298
341 void initSample(
342 std::size_t n,
343 std::function<void(api::model::GridAgent<CellType>*)> init_function
344 ) const;
345
392 template<typename T>
393 void initSequence(
394 const std::vector<T>& items,
395 std::function<void(
397 typename std::vector<T>::const_reference
398 )> init_function
399 ) const;
400 };
401
402 template<typename CellType>
408 ) {
409 this->build(model, groups, [&factory] () {return factory.build();}, agent_mapping);
410 }
411
412 template<typename CellType>
416 std::function<api::model::SpatialAgent<CellType>*()> factory,
418 ) {
419 for(auto cell : model.cells()) {
420 std::size_t count = agent_mapping.countAt(cell);
421 if(count > 0)
422 // Does not insert useless null entries
423 item_counts[cell->location()]=count;
424 }
425
426 // Gather item counts from all processes
427 communication::TypedMpi<decltype(item_counts)> item_counts_mpi(
428 model.getMpiCommunicator());
429 item_counts =
430 communication::all_reduce(item_counts_mpi, item_counts, utils::Concat());
431
432 // Contains the current index of agents located at each location
433 std::map<DiscretePoint, std::size_t> local_counts;
434
435 // Built agents
436 std::vector<api::model::GridAgent<CellType>*> agents;
437
438 this->build_agents(model, groups, [&agents, &factory] {
439 auto agent = factory();
440 // Keep a reference to built agents
441 agents.push_back((api::model::GridAgent<CellType>*) agent);
442 return agent;
443 }, agent_mapping);
444
445 agent_begin = GridAgentIndex::begin(&item_counts);
446 agent_end = GridAgentIndex::end(&item_counts);
447
448 for(std::size_t i = 0; i < agents.size(); i++) {
449 std::size_t& offset = local_counts[agents[i]->locationPoint()];
450 GridAgentIndex index(&item_counts, agents[i]->locationPoint(), offset);
451 agent_index.insert({index, agents[i]});
452
453 ++offset;
454
455 // Generates seed from the current localion random number
456 // generator (RNG).
457 // Since the grid cell RNG initialization does not depend on
458 // the current distribution, the grid agents RNG does not
459 // depend neither on the distribution (i.e. the agent with the
460 // current `index` is **always** associated to the same seed)
461 agents[i]->seed(agents[i]->locationCell()->rd()());
462 }
463 }
464
465 template<typename CellType>
467 std::size_t n,
468 std::function<void(api::model::GridAgent<CellType>*)> init_function
469 ) const {
470 std::vector<GridAgentIndex> indexes = random::sample_indexes(
471 agent_begin, agent_end, n, RandomGridAgentBuilder::rd);
472 for(auto index : indexes) {
473 auto it = agent_index.find(index);
474 if(it != agent_index.end())
475 init_function(it->second);
476 }
477 }
478
479 template<typename CellType>
480 template<typename T>
482 const std::vector<T> &items,
483 std::function<void (
485 typename std::vector<T>::const_reference
486 )> init_function) const {
487 GridAgentIndex grid_index = agent_begin;
488 auto map_index = agent_index.begin();
489 std::size_t i = 0;
490 while(map_index != agent_index.end()) {
491 if(map_index->first == grid_index) {
492 init_function(
493 map_index->second,
494 items[i]
495 );
496 ++map_index;
497 }
498 ++grid_index;
499 ++i;
500 }
501 }
502
506 template<typename BuilderType, typename DistanceType, typename _CellType = model::GridCell>
507 struct GridConfig {
512 typedef BuilderType Builder;
533 typedef DistanceType Distance;
534
541 typedef _CellType CellType;
542 };
543
547 template<typename DistanceType, typename PerimeterType>
573 typedef DistanceType Distance;
574
594 typedef PerimeterType Perimeter;
595 };
596
622 template<typename GridConfig, typename GridRangeConfig>
623 class GridRange : public api::model::Range<typename GridConfig::CellType> {
624 private:
625 static const typename GridConfig::Distance grid_distance;
626 static const typename GridRangeConfig::Distance range_distance;
627 static const typename GridRangeConfig::Perimeter perimeter;
629
630 public:
637 : size(size) {}
638
645 return size;
646 }
647
658 this->size = size;
659 }
660
672 typename GridConfig::CellType* location_cell,
673 typename GridConfig::CellType* cell) const override {
674 if(this->getSize() < 0)
675 return false;
676 else
677 return range_distance(location_cell->location(), cell->location()) <= size;
678 }
679
694 // TODO: provide a figure with examples for VN range / VN
695 // grid, VN range / Moore grid, Moore range / VN grid and
696 // Moore range / Moore grid.
697 std::size_t radius(typename GridConfig::CellType*) const override {
698 return grid_distance({0, 0}, perimeter(*this));
699 }
700 };
701
702 template<typename GridConfig, typename RangeConfig>
703 const typename GridConfig::Distance GridRange<GridConfig, RangeConfig>::grid_distance;
704 template<typename GridConfig, typename RangeConfig>
705 const typename RangeConfig::Distance GridRange<GridConfig, RangeConfig>::range_distance;
706 template<typename GridConfig, typename RangeConfig>
707 const typename RangeConfig::Perimeter GridRange<GridConfig, RangeConfig>::perimeter;
708
712 template<
713 template<typename> class SyncMode,
714 typename CellType = model::GridCell,
715 typename EndCondition = DynamicEndCondition<CellType>>
717}}
718
721
722namespace nlohmann {
727 template<>
728 struct adl_serializer<fpmas::api::model::DiscretePoint> {
735 static void to_json(nlohmann::json& j, const fpmas::api::model::DiscretePoint& point) {
736 j = {point.x, point.y};
737 }
746 static void from_json(const nlohmann::json& j, fpmas::api::model::DiscretePoint& point) {
747 point.x = j[0].get<fpmas::api::model::DiscreteCoordinate>();
748 point.y = j[1].get<fpmas::api::model::DiscreteCoordinate>();
749 }
750 };
751
755 template<typename GridCellType, typename Derived>
756 struct adl_serializer<fpmas::api::utils::PtrWrapper<fpmas::model::GridCellBase<GridCellType, Derived>>> {
761
777 static void to_json(nlohmann::json& j, const Ptr& ptr) {
778 // Derived serialization
780 const_cast<Derived*>(static_cast<const Derived*>(ptr.get())));
781 // Current base serialization
782 j[1] = ptr->_location;
783 j[2] = ptr->_rd;
784 }
785
804 static Ptr from_json(const nlohmann::json& j) {
805 // Derived unserialization.
806 // The current base is implicitly default initialized
809
810 // Initializes the current base
811 derived_ptr->_location = j[1].get<fpmas::api::model::DiscretePoint>();
812 derived_ptr->_rd = j[2].get<fpmas::random::FPMAS_AGENT_RNG>();
813 return derived_ptr.get();
814 }
815 };
816
820 template<typename AgentType, typename CellType, typename Derived>
821 struct adl_serializer<fpmas::api::utils::PtrWrapper<fpmas::model::GridAgent<AgentType, CellType, Derived>>> {
826
842 static void to_json(nlohmann::json& j, const Ptr& ptr) {
843 // Derived serialization
845 const_cast<Derived*>(static_cast<const Derived*>(ptr.get())));
846 // Current base serialization
847 j[1] = ptr->location_point;
848 j[2] = ptr->_rd;
849 }
850
869 static Ptr from_json(const nlohmann::json& j) {
870 // Derived unserialization.
871 // The current base is implicitly default initialized
874
875 // Initializes the current base
876 derived_ptr->location_point = j[1].get<fpmas::api::model::DiscretePoint>();
877 derived_ptr->_rd = j[2].get<fpmas::random::FPMAS_AGENT_RNG>();
878 return derived_ptr.get();
879 }
880 };
881
882}
883
884namespace fpmas { namespace io { namespace json {
885
896 template<typename GridCellType, typename Derived>
897 struct light_serializer<PtrWrapper<fpmas::model::GridCellBase<GridCellType, Derived>>> {
914 static void to_json(light_json& j, const Ptr& cell) {
915 // Derived serialization
917 j,
918 const_cast<Derived*>(static_cast<const Derived*>(cell.get()))
919 );
920 }
921
934 static Ptr from_json(const light_json& j) {
935 // Derived unserialization.
936 // The current base is implicitly default initialized
937 PtrWrapper<Derived> derived_ptr
939 return derived_ptr.get();
940 }
941 };
942
954 template<typename AgentType, typename CellType, typename Derived>
955 struct light_serializer<PtrWrapper<fpmas::model::GridAgent<AgentType, CellType, Derived>>> {
960
973 static void to_json(light_json& j, const Ptr& agent) {
974 // Derived serialization
976 j,
977 const_cast<Derived*>(static_cast<const Derived*>(agent.get()))
978 );
979 }
980
993 static Ptr from_json(const light_json& j) {
994 // Derived unserialization.
995 // The current base is implicitly default initialized
996 PtrWrapper<Derived> derived_ptr
998 return derived_ptr.get();
999 }
1000 };
1001
1002}}}
1003
1004namespace fpmas { namespace io { namespace datapack {
1022 template<typename GridCellType, typename Derived>
1023 struct Serializer<PtrWrapper<fpmas::model::GridCellBase<GridCellType, Derived>>> {
1028
1033 static std::size_t size(const ObjectPack& p, const Ptr& ptr) {
1035 const_cast<Derived*>(static_cast<const Derived*>(ptr.get())));
1036 return p.size(derived) + p.size<api::model::DiscretePoint>()
1037 + p.size(ptr->_rd);
1038 }
1039
1047 static void to_datapack(ObjectPack& pack, const Ptr& ptr) {
1048 // Derived serialization
1050 const_cast<Derived*>(static_cast<const Derived*>(ptr.get())));
1051 pack.put(derived);
1052 // Current base serialization (only location is needed)
1053 pack.put(ptr->_location);
1054 pack.put(ptr->_rd);
1055 }
1056
1075 static Ptr from_datapack(const ObjectPack& pack) {
1076 // Derived unserialization.
1077 // The current base is implicitly default initialized
1078 PtrWrapper<Derived> derived_ptr = pack
1080
1081 // Initializes the current base
1082 derived_ptr->_location = pack.get<fpmas::api::model::DiscretePoint>();
1083 derived_ptr->_rd = pack.get<fpmas::random::FPMAS_AGENT_RNG>();
1084 return derived_ptr.get();
1085 }
1086 };
1087
1106 template<typename AgentType, typename CellType, typename Derived>
1107 struct Serializer<PtrWrapper<fpmas::model::GridAgent<AgentType, CellType, Derived>>> {
1112
1117 static std::size_t size(const ObjectPack& p, const Ptr& ptr) {
1118 return p.size(PtrWrapper<Derived>(
1119 const_cast<Derived*>(static_cast<const Derived*>(ptr.get()))))
1121 + p.size(ptr->_rd);
1122 }
1123
1131 static void to_datapack(ObjectPack& pack, const Ptr& ptr) {
1132 // Derived serialization
1134 const_cast<Derived*>(static_cast<const Derived*>(ptr.get())));
1135 pack.put(derived);
1136 // Current base serialization
1137 pack.put(ptr->location_point);
1138 pack.put(ptr->_rd);
1139 }
1140
1159 static Ptr from_datapack(const ObjectPack& pack) {
1160 // Derived unserialization.
1161 // The current base is implicitly default initialized
1162 PtrWrapper<Derived> derived_ptr = pack
1164
1165 // Initializes the current base
1166 derived_ptr->location_point =
1168 derived_ptr->_rd = pack.get<fpmas::random::FPMAS_AGENT_RNG>();
1169 return derived_ptr.get();
1170 }
1171 };
1172
1192 template<typename GridCellType, typename Derived>
1193 struct LightSerializer<PtrWrapper<fpmas::model::GridCellBase<GridCellType, Derived>>> {
1198
1204 static std::size_t size(const LightObjectPack& p, const Ptr& ptr) {
1205 return p.size(PtrWrapper<Derived>(
1206 const_cast<Derived*>(static_cast<const Derived*>(ptr.get()))
1207 ));
1208 }
1209
1222 static void to_datapack(LightObjectPack& pack, const Ptr& cell) {
1223 // Derived serialization
1225 pack,
1226 const_cast<Derived*>(static_cast<const Derived*>(cell.get()))
1227 );
1228 }
1229
1242 static Ptr from_datapack(const LightObjectPack& pack) {
1243 // Derived unserialization.
1244 // The current base is implicitly default initialized
1245 PtrWrapper<Derived> derived_ptr
1247 return derived_ptr.get();
1248 }
1249 };
1250
1271 template<typename AgentType, typename CellType, typename Derived>
1272 struct LightSerializer<PtrWrapper<fpmas::model::GridAgent<AgentType, CellType, Derived>>> {
1277
1283 static std::size_t size(const LightObjectPack& p, const Ptr& ptr) {
1284 return p.size(PtrWrapper<Derived>(
1285 const_cast<Derived*>(static_cast<const Derived*>(ptr.get()))
1286 ));
1287 }
1288
1301 static void to_datapack(LightObjectPack& pack, const Ptr& agent) {
1302 // Derived serialization
1304 pack,
1305 const_cast<Derived*>(static_cast<const Derived*>(agent.get()))
1306 );
1307 }
1308
1321 static Ptr from_datapack(const LightObjectPack& pack) {
1322 // Derived unserialization.
1323 // The current base is implicitly default initialized
1324 PtrWrapper<Derived> derived_ptr
1326 return derived_ptr.get();
1327 }
1328 };
1329
1336 template<>
1343 static std::size_t size(const ObjectPack& p);
1344
1348 static std::size_t size(const ObjectPack& p, const api::model::DiscretePoint&);
1349
1356 static void to_datapack(
1357 ObjectPack& pack, const api::model::DiscretePoint& point);
1358
1365 static api::model::DiscretePoint from_datapack(const ObjectPack& pack);
1366 };
1367}}}
1368
1369namespace std {
1373 template<>
1374 struct hash<fpmas::model::DiscretePoint> {
1385 std::size_t operator()(const fpmas::model::DiscretePoint& p) const;
1386 };
1387}
1388#endif
#define FPMAS_AGENT_RNG
Definition: model.h:32
Definition: grid.h:147
Definition: grid.h:78
virtual api::communication::MpiCommunicator & getMpiCommunicator()=0
Definition: spatial_model.h:121
Definition: spatial_model.h:607
virtual SpatialAgent< CellType > * build()=0
virtual std::size_t countAt(CellType *cell)=0
Definition: spatial_model.h:234
virtual std::vector< CellType * > cells()=0
Definition: ptr_wrapper.h:21
T * get()
Definition: ptr_wrapper.h:58
Definition: datapack.h:301
std::size_t size() const
Definition: datapack.h:367
void put(const T &item)
Definition: datapack.h:447
T get() const
Definition: datapack.h:459
Definition: spatial_model.h:215
Definition: grid.h:258
void initSequence(const std::vector< T > &items, std::function< void(api::model::GridAgent< CellType > *, typename std::vector< T >::const_reference)> init_function) const
Definition: grid.h:481
void build(api::model::SpatialModel< CellType > &model, api::model::GroupList groups, api::model::SpatialAgentFactory< CellType > &factory, api::model::SpatialAgentMapping< api::model::GridCell > &agent_mapping) override
Definition: grid.h:403
void initSample(std::size_t n, std::function< void(api::model::GridAgent< CellType > *)> init_function) const
Definition: grid.h:466
Definition: grid.h:121
void moveTo(GridCellType *cell) override
Definition: grid.h:158
void seed(std::FPMAS_AGENT_RNG::result_type seed) override
Definition: grid.h:152
random::FPMAS_AGENT_RNG & rd() override
Definition: grid.h:148
DiscretePoint locationPoint() const override
Definition: grid.h:146
Definition: grid.h:51
GridCellBase()
Definition: grid.h:68
random::FPMAS_AGENT_RNG & rd() override
Definition: grid.h:88
void seed(random::FPMAS_AGENT_RNG::result_type seed) override
Definition: grid.h:95
DiscretePoint location() const override
Definition: grid.h:81
GridCellBase< GridCellType, Derived > JsonBase
Definition: grid.h:63
GridCellBase(DiscretePoint location)
Definition: grid.h:75
Definition: grid.h:188
GridCellType * build(DiscretePoint location) override
Definition: grid.h:198
Definition: grid.h:104
Definition: grid.h:623
std::size_t radius(typename GridConfig::CellType *) const override
Definition: grid.h:697
DiscreteCoordinate getSize() const
Definition: grid.h:644
GridRange(DiscreteCoordinate size)
Definition: grid.h:636
bool contains(typename GridConfig::CellType *location_cell, typename GridConfig::CellType *cell) const override
Definition: grid.h:671
void setSize(DiscreteCoordinate size)
Definition: grid.h:657
Definition: spatial_model.h:756
Definition: spatial_model.h:1087
Definition: spatial_model.h:674
Definition: generator.h:113
UniformRandomBitGenerator< Generator_t >::result_type result_type
Definition: generator.h:120
static Index end(const std::map< DiscretePoint, std::size_t > *item_counts)
Definition: random.h:479
static Index begin(const std::map< DiscretePoint, std::size_t > *item_counts)
Definition: random.h:471
#define FPMAS_DEFAULT_DATAPACK(AGENT)
Definition: datapack_serializer.h:154
#define FPMAS_DEFAULT_JSON(AGENT)
Definition: json_serializer.h:127
std::vector< std::reference_wrapper< AgentGroup > > GroupList
Definition: model.h:833
long DiscreteCoordinate
Definition: grid.h:15
T all_reduce(api::communication::TypedMpi< T > &mpi, const T &data, BinaryOp binary_op=BinaryOp())
Definition: communication.h:634
nlohmann::basic_json< std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, light_serializer > light_json
Definition: json.h:14
random::Index< DiscretePoint > GridAgentIndex
Definition: grid.h:223
std::vector< Index_t > sample_indexes(Index_t begin, Index_t end, std::size_t n, Generator_t &gen)
Definition: random.h:292
Definition: fpmas.cpp:3
void seed(unsigned long seed)
Definition: fpmas.cpp:23
DiscreteCoordinate x
Definition: grid.h:25
DiscreteCoordinate y
Definition: grid.h:29
Definition: communication.h:585
static std::size_t size(const LightObjectPack &p, const Ptr &ptr)
Definition: grid.h:1283
PtrWrapper< fpmas::model::GridAgent< AgentType, CellType, Derived > > Ptr
Definition: grid.h:1276
static void to_datapack(LightObjectPack &pack, const Ptr &agent)
Definition: grid.h:1301
static std::size_t size(const LightObjectPack &p, const Ptr &ptr)
Definition: grid.h:1204
static void to_datapack(LightObjectPack &pack, const Ptr &cell)
Definition: grid.h:1222
PtrWrapper< fpmas::model::GridCellBase< GridCellType, Derived > > Ptr
Definition: grid.h:1197
Definition: datapack.h:1411
static void to_datapack(LightObjectPack &pack, const T &item)
Definition: datapack.h:1438
static T from_datapack(const LightObjectPack &pack)
Definition: datapack.h:1451
static std::size_t size(const ObjectPack &p, const Ptr &ptr)
Definition: grid.h:1117
static void to_datapack(ObjectPack &pack, const Ptr &ptr)
Definition: grid.h:1131
PtrWrapper< fpmas::model::GridAgent< AgentType, CellType, Derived > > Ptr
Definition: grid.h:1111
static std::size_t size(const ObjectPack &p, const Ptr &ptr)
Definition: grid.h:1033
PtrWrapper< fpmas::model::GridCellBase< GridCellType, Derived > > Ptr
Definition: grid.h:1027
static void to_datapack(ObjectPack &pack, const Ptr &ptr)
Definition: grid.h:1047
Definition: datapack.h:55
PtrWrapper< fpmas::model::GridAgent< AgentType, CellType, Derived > > Ptr
Definition: grid.h:959
PtrWrapper< fpmas::model::GridCellBase< GridCellType, Derived > > Ptr
Definition: grid.h:901
static void from_json(const light_json &j, T &data)
Definition: json.h:123
static void to_json(light_json &j, const T &data)
Definition: json.h:107
Definition: grid.h:507
_CellType CellType
Definition: grid.h:541
DistanceType Distance
Definition: grid.h:533
BuilderType Builder
Definition: grid.h:512
Definition: grid.h:548
DistanceType Distance
Definition: grid.h:573
PerimeterType Perimeter
Definition: grid.h:594
Definition: grid.h:22
std::size_t operator()(const DiscretePoint &p) const
Definition: grid.cpp:5
static random::mt19937_64 rd
Definition: grid.h:238
Definition: functional.h:94
static void to_json(nlohmann::json &j, const fpmas::api::model::DiscretePoint &point)
Definition: grid.h:735
static void from_json(const nlohmann::json &j, fpmas::api::model::DiscretePoint &point)
Definition: grid.h:746
fpmas::api::utils::PtrWrapper< fpmas::model::GridAgent< AgentType, CellType, Derived > > Ptr
Definition: grid.h:825
fpmas::api::utils::PtrWrapper< fpmas::model::GridCellBase< GridCellType, Derived > > Ptr
Definition: grid.h:760
static const fpmas::model::PointHash hasher
Definition: grid.h:1378