├── .cproject ├── .gitignore ├── .nedfolders ├── .oppbuildspec ├── .project ├── .settings └── org.eclipse.cdt.codan.core.prefs ├── Makefile ├── Makefile.vc ├── README.md ├── simulations ├── package.ned └── run ├── src ├── AmacadControlMessage.msg ├── AmacadData.h ├── AmacadNetworkLayer.cc ├── AmacadNetworkLayer.h ├── AmacadNetworkLayer.ned ├── AmacadWeightCluster.cc ├── AmacadWeightCluster.h ├── AmacadWeightCluster.ned ├── ClusterAlgorithm.cc ├── ClusterAlgorithm.h ├── ClusterAnalysisScenarioManager.cc ├── ClusterAnalysisScenarioManager.h ├── ClusterAnalysisScenarioManager.ned ├── ClusterDraw.cc ├── ClusterDraw.h ├── ExtendedRmacControlMessage.msg ├── ExtendedRmacNetworkLayer.cc ├── ExtendedRmacNetworkLayer.h ├── ExtendedRmacNetworkLayer.ned ├── HighestDegreeCluster.cc ├── HighestDegreeCluster.h ├── HighestDegreeCluster.ned ├── LSUFCluster.cc ├── LSUFCluster.h ├── LSUFCluster.ned ├── LSUFData.cc ├── LSUFData.h ├── LowestIdCluster.cc ├── LowestIdCluster.h ├── LowestIdCluster.ned ├── Makefile ├── MarcumQ.cc ├── MarcumQ.h ├── MdmacControlMessage.msg ├── MdmacNetworkLayer.cc ├── MdmacNetworkLayer.h ├── MdmacNetworkLayer.ned ├── RMACData.h ├── RmacControlMessage.msg ├── RmacNetworkLayer.cc ├── RmacNetworkLayer.h ├── RmacNetworkLayer.ned ├── RouteSimilarityCluster.cc ├── RouteSimilarityCluster.h ├── RouteSimilarityCluster.ned └── package.ned └── tools ├── ClusterAnalysis.py ├── GenerateGrid.py ├── LaneWeight.py └── OmnetReader.py /.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 36 | 37 | 41 | 42 | 43 | 44 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 98 | 99 | 100 | 101 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | *.app 10 | *.build 11 | *.luao 12 | 13 | # Packages # 14 | ############ 15 | # it's better to unpack these files and commit the raw source 16 | # git has its own built in compression methods 17 | *.7z 18 | *.dmg 19 | *.gz 20 | *.iso 21 | *.jar 22 | *.rar 23 | *.tar 24 | *.zip 25 | 26 | # Logs and databases # 27 | ###################### 28 | *.log 29 | *.sql 30 | *.sqlite 31 | 32 | # OS generated files # 33 | ###################### 34 | .DS_Store 35 | .DS_Store? 36 | ._* 37 | .Spotlight-V100 38 | .Trashes 39 | Icon? 40 | ehthumbs.db 41 | Thumbs.db 42 | .unison* 43 | 44 | # folders # 45 | ########### 46 | out 47 | -------------------------------------------------------------------------------- /.nedfolders: -------------------------------------------------------------------------------- 1 | URAE/ned 2 | simulations 3 | src 4 | -------------------------------------------------------------------------------- /.oppbuildspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | ClusterLib 4 | 5 | 6 | veins-2.0 7 | 8 | 9 | 10 | org.omnetpp.cdt.MakefileBuilder 11 | 12 | 13 | 14 | 15 | org.omnetpp.scave.builder.vectorfileindexer 16 | 17 | 18 | 19 | 20 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 21 | clean,full,incremental, 22 | 23 | 24 | ?name? 25 | 26 | 27 | 28 | org.eclipse.cdt.make.core.append_environment 29 | true 30 | 31 | 32 | org.eclipse.cdt.make.core.autoBuildTarget 33 | all 34 | 35 | 36 | org.eclipse.cdt.make.core.buildArguments 37 | MODE=debug CONFIGNAME=${ConfigName} 38 | 39 | 40 | org.eclipse.cdt.make.core.buildCommand 41 | make 42 | 43 | 44 | org.eclipse.cdt.make.core.buildLocation 45 | ${ProjDirPath} 46 | 47 | 48 | org.eclipse.cdt.make.core.cleanBuildTarget 49 | clean 50 | 51 | 52 | org.eclipse.cdt.make.core.contents 53 | org.eclipse.cdt.make.core.activeConfigSettings 54 | 55 | 56 | org.eclipse.cdt.make.core.enableAutoBuild 57 | false 58 | 59 | 60 | org.eclipse.cdt.make.core.enableCleanBuild 61 | true 62 | 63 | 64 | org.eclipse.cdt.make.core.enableFullBuild 65 | true 66 | 67 | 68 | org.eclipse.cdt.make.core.fullBuildTarget 69 | all 70 | 71 | 72 | org.eclipse.cdt.make.core.stopOnError 73 | true 74 | 75 | 76 | org.eclipse.cdt.make.core.useDefaultBuildCmd 77 | true 78 | 79 | 80 | 81 | 82 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 83 | full,incremental, 84 | 85 | 86 | 87 | 88 | 89 | org.eclipse.cdt.core.cnature 90 | org.eclipse.cdt.core.ccnature 91 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 92 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 93 | org.omnetpp.main.omnetppnature 94 | 95 | 96 | -------------------------------------------------------------------------------- /.settings/org.eclipse.cdt.codan.core.prefs: -------------------------------------------------------------------------------- 1 | #Wed May 15 15:19:43 EST 2013 2 | eclipse.preferences.version=1 3 | org.eclipse.cdt.codan.checkers.errnoreturn=Warning 4 | org.eclipse.cdt.codan.checkers.errnoreturn.params={implicit\=>false} 5 | org.eclipse.cdt.codan.checkers.errreturnvalue=Error 6 | org.eclipse.cdt.codan.checkers.errreturnvalue.params={} 7 | org.eclipse.cdt.codan.checkers.noreturn=Error 8 | org.eclipse.cdt.codan.checkers.noreturn.params={implicit\=>false} 9 | org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error 10 | org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 11 | org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error 12 | org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 13 | org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning 14 | org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={} 15 | org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error 16 | org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={} 17 | org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning 18 | org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} 19 | org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning 20 | org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={unknown\=>false,exceptions\=>()} 21 | org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error 22 | org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 23 | org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error 24 | org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 25 | org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error 26 | org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 27 | org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error 28 | org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 29 | org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error 30 | org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 31 | org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error 32 | org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 33 | org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error 34 | org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 35 | org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error 36 | org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 37 | org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info 38 | org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} 39 | org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning 40 | org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={} 41 | org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error 42 | org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 43 | org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error 44 | org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 45 | org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error 46 | org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 47 | org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning 48 | org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={} 49 | org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning 50 | org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={} 51 | org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning 52 | org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={macro\=>true,exceptions\=>()} 53 | org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning 54 | org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={paramNot\=>false} 55 | org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning 56 | org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={else\=>false,afterelse\=>false} 57 | org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error 58 | org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 59 | org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning 60 | org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={macro\=>true} 61 | org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning 62 | org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={macro\=>true} 63 | org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning 64 | org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={macro\=>true,exceptions\=>("@(\#)","$Id")} 65 | org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error 66 | org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 67 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: checkmakefiles 2 | cd src && $(MAKE) 3 | 4 | clean: checkmakefiles 5 | cd src && $(MAKE) clean 6 | 7 | cleanall: checkmakefiles 8 | cd src && $(MAKE) MODE=release clean 9 | cd src && $(MAKE) MODE=debug clean 10 | rm -f src/Makefile 11 | 12 | makefiles: 13 | cd src && opp_makemake -f --deep 14 | 15 | checkmakefiles: 16 | @if [ ! -f src/Makefile ]; then \ 17 | echo; \ 18 | echo '======================================================================='; \ 19 | echo 'src/Makefile does not exist. Please use "make makefiles" to generate it!'; \ 20 | echo '======================================================================='; \ 21 | echo; \ 22 | exit 1; \ 23 | fi 24 | -------------------------------------------------------------------------------- /Makefile.vc: -------------------------------------------------------------------------------- 1 | all: checkmakefiles 2 | cd src && $(MAKE) -f Makefile.vc 3 | 4 | clean: checkmakefiles 5 | cd src && $(MAKE) -f Makefile.vc clean 6 | 7 | cleanall: checkmakefiles 8 | cd src && $(MAKE) -f Makefile.vc MODE=release clean 9 | cd src && $(MAKE) -f Makefile.vc MODE=debug clean 10 | 11 | makefiles: 12 | cd src && call opp_nmakemake -f --deep 13 | 14 | checkmakefiles: 15 | @if not exist src\Makefile.vc ( \ 16 | echo. && \ 17 | echo ============================================================================ && \ 18 | echo src/Makefile.vc does not exist. Please use the following command to generate it: && \ 19 | echo nmake -f Makefile.vc makefiles && \ 20 | echo ============================================================================ && \ 21 | echo. && \ 22 | exit 1 ) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ClusterLib 2 | ========== 3 | 4 | Implementations of a selection of clustering algorithms for VANETs, written in C++ for OMNeT++ 5 | 6 | Supported clustering algorithms: 7 | 8 | - Modified Distributed Mobility-Aware Clustering (MDMAC), by Wolny et al. 9 | Class name: MdmacNetworkLayer 10 | 11 | - Adaptive Mobility-Aware Clustering Algorithm with Destination (AMACAD), by Morales et al. 12 | Class name: AmacadNetworkLayer 13 | 14 | - Robust Mobility Adaptive Clustering (RMAC), by Goonewardene et al. 15 | Class name: RmacNetworkLayer 16 | 17 | - Channel and Route Aware Clustering (CRAC), by Cooper et al. 18 | Class name: ExtendedRmacNetworkLayer 19 | 20 | MDMAC also implements a number of clustering metrics: 21 | 22 | - Lowest ID; Class name: LowestIdCluster 23 | 24 | - Highest Degree; Class name: HighestDegreeCluster 25 | 26 | - Lane-Sense Utility Function, by Almalag et al.; Class name: LSUFCluster 27 | 28 | - Route Similarity, which counts the consecutive common route links between two nodes, by Cooper et al 29 | Class name: RouteSimilarityCluster 30 | 31 | - Destination Analysis, similar to AMACAD's weight; Class name: AmacadWeightCluster 32 | 33 | To compile these you need OMNeT++ 4.2 or later (http://omnetpp.org/), VEINS 2.0 (http://veins.car2x.org/), and Urban Radio Channel (https://github.com/cscooper/URC). 34 | 35 | Email me at andor734@gmail.com or craigsco@bigpond.net.au if you have questions. 36 | 37 | Publications: 38 | 39 | G. Wolny, “Modified dmac clustering algorithm for vanets,” in Systems 40 | and Networks Communications, 2008. ICSNC ’08. 3rd International 41 | Conference on, 2008, pp. 268–273 42 | 43 | M. Morales, C. seon Hong, and Y. C. Bang, “An adaptable mobility- 44 | aware clustering algorithm in vehicular networks,” in Network Opera- 45 | tions and Management Symposium (APNOMS), 2011 13th Asia-Pacific, 46 | Sept 2011, pp. 1–6. 47 | 48 | M. Morales, E. J. Cho, C. seon Hong, and S. Lee, “An adaptable 49 | mobility-aware clustering algorithm in vehicular networks,” Journal of 50 | Computing Science and Engineering, vol. 6, pp. 227–242, Sept 2012. 51 | 52 | R. Goonewardene, F. Ali, and E. Stipidis, “Robust mobility adaptive 53 | clustering scheme with support for geographic routing for vehicular ad 54 | hoc networks,” IET Intell. Transp. Syst., vol. 3, no. 2, p. 148, 2009. 55 | 56 | C. Cooper , M. Ros, F. Safaei, D. Franklin, M. Abolhasan, "Simulation 57 | of Contrasting Clustering Paradigms under an Experimentally-derived 58 | Channel Model", IEEE Vehicular Technology Conference (VTC2014-Fall), 59 | Vancouver, Canada, 2014 60 | 61 | M. Almalag and M. Weigle, “Using traffic flow for cluster formation in 62 | vehicular ad-hoc networks,” in Local Computer Networks (LCN), 2010 63 | IEEE 35th Conference on, 2010, pp. 631–636. 64 | 65 | C. Cooper and A. Mukunthan, “Urban radio channel,” 2014. [Online]. 66 | Available: https://github.com/cscooper/URC 67 | 68 | 69 | -------------------------------------------------------------------------------- /simulations/package.ned: -------------------------------------------------------------------------------- 1 | package clusterlib.simulations; 2 | 3 | @license(LGPL); 4 | -------------------------------------------------------------------------------- /simulations/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd `dirname $0` 3 | ../src/clusterlib -n .:../src $* 4 | # for shared lib, use: opp_run -l ../src/clusterlib -n .:../src $* 5 | -------------------------------------------------------------------------------- /src/AmacadControlMessage.msg: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | cplusplus {{ 17 | #include "NetwPkt_m.h" 18 | #include "AmacadData.h" 19 | }} 20 | packet NetwPkt; 21 | 22 | class noncobject NeighbourEntrySet; 23 | class noncobject NeighbourIdSet; 24 | 25 | // 26 | // Describes the AMACAD cluster control message. 27 | // Extends the NetwPkt, so this can be used to encapsulate 28 | // application layer packets as well. 29 | // 30 | packet AmacadControlMessage extends NetwPkt { 31 | 32 | int nodeId; // Identifier of the neighbour. 33 | double xPosition; // X-Position of the neighbour. 34 | double yPosition; // Y-Position of the neighbour. 35 | double speed; // Speed of the neighbour. 36 | double xDestination; // X-Destination of the neighbour. 37 | double yDestination; // Y-Destination of the neighbour. 38 | bool isClusterHead; // Is this node a CH or CHM? 39 | int clusterHead; // The cluster head of this node. 40 | int neighbourCount; // Number of neighbours this node has. 41 | int clusterSize; // If CH, this is the number of nodes in its cluster. 42 | NeighbourEntrySet clusterTable; // Cluster Member table. 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/AmacadData.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef AMACADDATA_H_ 17 | #define AMACADDATA_H_ 18 | 19 | class AmacadNetworkLayer; 20 | 21 | /** 22 | * @brief Contains an entry in the AMACAD neighbour table. 23 | */ 24 | struct NeighbourEntry { 25 | unsigned int mId; /**< Identifier of the neighbour. */ 26 | LAddress::L3Type mNetworkAddress; /**< The IP address of this neighbour. */ 27 | double mPositionX; /**< X Position of this node. */ 28 | double mPositionY; /**< Y Position of this node. */ 29 | double mSpeed; /**< Speed of the node. */ 30 | double mDestinationX; /**< X Destination of the node in euclidean coordinates. */ 31 | double mDestinationY; /**< Y Destination of the node in euclidean coordinates. */ 32 | int mNeighbourCount; /**< Size of this node's neighbour table. */ 33 | int mClusterHead; /**< ID of this node's CH. */ 34 | bool mIsClusterHead; /**< Is this node a CH? */ 35 | int mClusterSize; /**< Size of this node's cluster, if CH. */ 36 | simtime_t mLastHeard; /**< Time since we last heard from this node. */ 37 | }; 38 | 39 | typedef std::vector NeighbourEntrySet; 40 | typedef NeighbourEntrySet::iterator NeighbourEntrySetIterator; 41 | 42 | typedef std::vector NeighbourIdSet; 43 | typedef NeighbourIdSet::iterator NeighbourIdSetIterator; 44 | 45 | #endif /* #define AMACADDATA_H_ */ 46 | -------------------------------------------------------------------------------- /src/AmacadNetworkLayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef AMACADNETWORKLAYER_H_ 17 | #define AMACADNETWORKLAYER_H_ 18 | 19 | #include 20 | 21 | #include "ClusterAlgorithm.h" 22 | #include "AmacadControlMessage_m.h" 23 | 24 | class AmacadNetworkLayer: public ClusterAlgorithm { 25 | 26 | public: 27 | AmacadNetworkLayer(); 28 | virtual ~AmacadNetworkLayer(); 29 | 30 | virtual int GetStateCount(); 31 | virtual int GetClusterState(); 32 | virtual bool IsClusterHead(); 33 | virtual bool IsSubclusterHead(); 34 | virtual bool IsHierarchical(); 35 | virtual int GetMinimumClusterSize(); 36 | 37 | virtual void UpdateMessageString(); 38 | 39 | /** @brief Initialization of the module and some variables*/ 40 | virtual void initialize(int); 41 | 42 | /** @brief Cleanup*/ 43 | virtual void finish(); 44 | 45 | protected: 46 | 47 | enum ClusterMessageKinds { 48 | AFFILIATION_MESSAGE = LAST_BASE_NETW_MESSAGE_KIND+1, /**< Message for unclustered nodes to find CHs. */ 49 | AFFILIATION_ACK_MESSAGE, /**< Affiliation ACK message. */ 50 | HELLO_MESSAGE, /**< Inquiry frame. */ 51 | HELLO_ACK_MESSAGE, /**< Inquiry response. */ 52 | ADD_MESSAGE, /**< Request to join a cluster. */ 53 | MEMBER_ACK_MESSAGE, /**< Response to allow a member to join a cluster. */ 54 | CLUSTERHEAD_ACK_MESSAGE, /**< Response requiring a new member to become a CH. */ 55 | MEMBER_UPDATE_MESSAGE, /**< Tell cluster members to change to a new CH. */ 56 | DELETE_MESSAGE, /**< A CM has left the cluster. */ 57 | WARNING_MESSAGE, /**< Message warning a CH of a significant change in speed or bandwidth. */ 58 | RECLUSTERING_MESSAGE, /**< Message to trigger a reclustering process. */ 59 | RECLUSTERING_ACK_MESSAGE, /**< Response to the reclustering message. */ 60 | DATA /**< Data packet. */ 61 | }; 62 | 63 | enum ClusterState { 64 | Unclustered = 0, /**< Initial state. Send out an affiliation message. */ 65 | //NeighbourDiscovery, /**< We've declared ourselves a CH, and start looking for our neighbours. */ 66 | Joining, /**< We've found a suitable CH, and are trying to join it. */ 67 | ClusterMember, /**< We're a CM. */ 68 | ClusterHead, /**< We're a CH. */ 69 | Reclustering /**< We're in the middle of a reclustering process. */ 70 | }; 71 | 72 | struct DestinationEntry { 73 | double mTime; /**< The time until which this is our destination. */ 74 | Coord mDestination; /**< The coordinates of this destination. */ 75 | }; 76 | 77 | typedef std::vector DestinationSet; 78 | 79 | struct Neighbour { 80 | 81 | int mId; /**< ID of the node. */ 82 | LAddress::L3Type mNetworkAddress; /**< The IP address of this neighbour. */ 83 | Coord mPosition; /**< Position of this node. */ 84 | double mSpeed; /**< Speed of the node. */ 85 | Coord mDestination; /**< Destination of the node in euclidean coordinates. */ 86 | double mValueF; /**< Fvz calculated for this node. */ 87 | int mNeighbourCount; /**< Size of this node's neighbour table. */ 88 | int mClusterHead; /**< ID of this node's CH. */ 89 | bool mIsClusterHead; /**< Is this node a CH? */ 90 | int mClusterSize; /**< Size of this node's cluster, if CH. */ 91 | 92 | simtime_t mLastHeard; /**< Time since we last heard from this node. */ 93 | 94 | }; 95 | 96 | typedef std::map NeighbourSet; 97 | typedef std::map::iterator NeighbourIterator; 98 | 99 | bool mInitialised; 100 | 101 | //int mId; /**< ID of this node. */ 102 | bool mIsClusterHead; /**< Is this node a CH? */ 103 | NeighbourSet mNeighbours; /**< This node's neighbour table. */ 104 | ClusterState mCurrentState; /**< State of the algorithm. */ 105 | NodeIdList mClusterHeadNeighbours; /**< Set of neighbours near CH. */ 106 | int mWarningMessageCount; /**< Number of warning messages. */ 107 | 108 | double mWeights[3]; /**< Set of weights. */ 109 | Coord mCurrentDestination; /**< Current destination. */ 110 | DestinationSet mDestinationSet; /**< Set of destinations. */ 111 | 112 | double mLastSpeed; /**< Last speed we calculated between our neighbours. */ 113 | double mLastBandwidth; /**< Last bandwidth we calculated between our neighbours. */ 114 | 115 | int mCurrentClusterHeadTarget; /**< The CH we're currently trying to affiliate with. */ 116 | 117 | /** 118 | * @name Handlers 119 | * @brief OMNeT++ message handler. 120 | * 121 | * These methods handle messages passed to this module. 122 | * 123 | **/ 124 | /*@{*/ 125 | 126 | /** @brief Handle messages from upper layer */ 127 | virtual void handleUpperMsg(cMessage* msg); 128 | 129 | /** @brief Handle messages from lower layer */ 130 | virtual void handleLowerMsg(cMessage* msg); 131 | 132 | /** @brief Handle self messages */ 133 | virtual void handleSelfMsg(cMessage* msg); 134 | 135 | /** @brief decapsulate higher layer message from RmacControlMessage */ 136 | virtual cMessage* decapsMsg(AmacadControlMessage*); 137 | 138 | /** @brief Encapsulate higher layer packet into a RmacControlMessage */ 139 | virtual NetwPkt* encapsMsg(cPacket*); 140 | 141 | /*@}*/ 142 | 143 | 144 | /** 145 | * Process the algorithm state machine. 146 | */ 147 | void Process( cMessage *msg = NULL ); 148 | 149 | 150 | 151 | /** 152 | * @brief Send a control message 153 | */ 154 | void SendControlMessage( int type, int destID = -1 ); 155 | 156 | 157 | 158 | /** 159 | * Update neighbour data with the given message. 160 | */ 161 | void UpdateNeighbour( AmacadControlMessage *m ); 162 | 163 | 164 | /** 165 | * Collect CH neighbours. 166 | */ 167 | void CollectClusterHeadNeighbours(); 168 | 169 | 170 | /** 171 | * Calculate the F value. 172 | */ 173 | double CalculateF( int id=-1 ); 174 | 175 | 176 | /** 177 | * Compute neighbour scores and return the ID of the best scoring one. 178 | */ 179 | int ComputeNeighbourScores(); 180 | 181 | 182 | /** 183 | * Change the CH. 184 | */ 185 | void ChangeCH( int ch = -1 ); 186 | 187 | 188 | /** 189 | * Get the destination from the destination file. 190 | */ 191 | void GetDestinationList(); 192 | 193 | 194 | /** 195 | * @name Messages 196 | * @brief Messages this module sends itself. 197 | * 198 | * These are used for timed events. 199 | * 200 | **/ 201 | /*@{*/ 202 | 203 | cMessage *mStartMessage; /**< Message to start processing. */ 204 | cMessage *mAffiliationTimeoutMessage; /**< Timeout for affiliation acknowledgements. */ 205 | cMessage *mJoinTimeoutMessage; /**< Timeout for JOIN acknowledgements. */ 206 | cMessage *mInquiryTimeoutMessage; /**< Timeout for inquiry period. */ 207 | cMessage *mUpdateMobilityMessage; /**< Signal to perform the reclustering. */ 208 | cMessage *mChangeDestinationMessage; /**< Signal to change the destination. */ 209 | 210 | /*@}*/ 211 | 212 | 213 | /** 214 | * @name Parameters 215 | * @brief Module parameters. 216 | * 217 | * These are uses to configure the algorithm. 218 | * 219 | **/ 220 | /*@{*/ 221 | 222 | int mMinimumDensity; /**< Minimum cluster size before reclustering. */ 223 | int mMaximumDensity; /**< Maximum cluster size permissible. */ 224 | int mMaximumClusterDensity; /**< Largest number of clusters in the neighbourhood. */ 225 | int mMaximumWarningCount; /**< Largest number of warning messages before changing CH. */ 226 | double mSpeedThreshold; /**< Speed difference threshold. */ 227 | double mBandwidthThreshold; /**< Bandwidth difference threshold. */ 228 | simtime_t mTimeDifference; /**< Time to wait between poll checking. */ 229 | simtime_t mTimeToLive; /**< Maximum lifetime of a neighbour table entry before it is considered dead. */ 230 | simtime_t mTimeoutPeriod; /**< Period of acknowledgement timeout. */ 231 | 232 | /*@}*/ 233 | 234 | }; 235 | 236 | #endif /* AMACADNETWORKLAYER_H_ */ 237 | -------------------------------------------------------------------------------- /src/AmacadNetworkLayer.ned: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | package clusterlib; 17 | 18 | import org.mixim.base.modules.BaseNetwLayer; 19 | 20 | // 21 | // This module implements the clustering mechanism for 22 | // AMACAD. 23 | // 24 | simple AmacadNetworkLayer extends BaseNetwLayer 25 | { 26 | parameters: 27 | @class(AmacadNetworkLayer); 28 | 29 | int minimumDensity; 30 | int maximumDensity; 31 | int maximumClusterDensity; 32 | int maximumWarningCount; 33 | double speedThreshold @unit("mps"); 34 | double bandwidthThreshold; 35 | double timeDifference @unit("s"); 36 | double timeToLive @unit("s"); 37 | double timeoutPeriod @unit("s"); 38 | 39 | double distanceWeight; 40 | double speedWeight; 41 | double destinationWeight; 42 | 43 | string destinationFile; 44 | 45 | // signals 46 | @signal[sigOverhead](type="int"); 47 | @signal[sigHelloOverhead](type="int"); 48 | @signal[sigClusterLifetime](type="double"); 49 | @signal[sigClusterSize](type="int"); 50 | @signal[sigHeadChange](type="int"); 51 | @signal[sigDeathType](type="int"); 52 | @signal[sigDeathX](type="double"); 53 | @signal[sigDeathY](type="double"); 54 | @signal[sigClusterDepth](type="int"); 55 | 56 | // statistics 57 | @statistic[ overhead]( source = sigOverhead; record = stats; title = "Overhead per node"; unit = "bytes" ); 58 | @statistic[ helloOverhead]( source = sigHelloOverhead; record = stats; title = "Overhead per node (HELLO messages)"; unit = "bytes" ); 59 | @statistic[clusterLifetime]( source = sigClusterLifetime; record = stats; title = "Cluster Lifetime"; unit = "s" ); 60 | @statistic[ clusterSize]( source = sigClusterSize; record = stats; title = "Cluster Size"; ); 61 | @statistic[ headChange]( source = "count(sigHeadChange)"; record = last; title = "CH changes"; ); 62 | @statistic[ deathType]( source = sigDeathType; record = vector; title = "Cluster Death Types"; ); 63 | @statistic[ deathX]( source = sigDeathX; record = vector; title = "Cluster Death Position X"; ); 64 | @statistic[ deathY]( source = sigDeathY; record = vector; title = "Cluster Death Position Y"; ); 65 | @statistic[ clusterDepth]( source = sigClusterDepth; record = stats; title = "Cluster Depth"; ); 66 | 67 | 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/AmacadWeightCluster.cc: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #include "BaseNetwLayer.h" 17 | 18 | #include 19 | 20 | #include "NetwControlInfo.h" 21 | #include "BaseMacLayer.h" 22 | #include "AddressingInterface.h" 23 | #include "SimpleAddress.h" 24 | #include "FindModule.h" 25 | #include "MdmacControlMessage_m.h" 26 | #include "ArpInterface.h" 27 | #include "NetwToMacControlInfo.h" 28 | #include "BaseMobility.h" 29 | #include "BaseConnectionManager.h" 30 | #include "ChannelAccess.h" 31 | 32 | 33 | #include "TraCIScenarioManager.h" 34 | #include "TraCIMobility.h" 35 | 36 | #include "AmacadWeightCluster.h" 37 | 38 | 39 | Define_Module(AmacadWeightCluster); 40 | 41 | 42 | 43 | /** @brief Initialization of the module and some variables*/ 44 | void AmacadWeightCluster::initialize( int stage ) { 45 | 46 | MdmacNetworkLayer::initialize( stage ); 47 | mIncludeDestination = true; 48 | if ( stage == 1 ) { 49 | 50 | mWeights[0] = par("distanceWeight").doubleValue(); 51 | mWeights[1] = par("speedWeight").doubleValue(); 52 | mWeights[2] = par("destinationWeight").doubleValue(); 53 | 54 | // Load this car's destination list. 55 | GetDestinationList(); 56 | 57 | // Schedule the change in destination. 58 | mChangeDestinationMessage = new cMessage( "changeDestination" ); 59 | scheduleAt( simTime() + mDestinationSet[0].mTime, mChangeDestinationMessage ); 60 | 61 | // Set up the first destination. 62 | mCurrentDestination = mDestinationSet[0].mDestination; 63 | 64 | // Clear the current destination in anticipation of the next one. 65 | mDestinationSet.erase( mDestinationSet.begin() ); 66 | 67 | } 68 | 69 | } 70 | 71 | 72 | 73 | /** @brief Handle self messages */ 74 | void AmacadWeightCluster::handleSelfMsg(cMessage* msg) { 75 | 76 | if ( mChangeDestinationMessage == msg ) { 77 | 78 | // We have to change the destination of our vehicle. 79 | if ( mDestinationSet.empty() ) 80 | return; 81 | 82 | // Trigger the change in destination. 83 | scheduleAt( simTime() + mDestinationSet[0].mTime, mChangeDestinationMessage ); 84 | 85 | // Set up the first destination. 86 | mCurrentDestination = mDestinationSet[0].mDestination; 87 | 88 | // Clear the current destination in anticipation of the next one. 89 | mDestinationSet.erase( mDestinationSet.begin() ); 90 | 91 | return; 92 | 93 | } else { 94 | 95 | MdmacNetworkLayer::handleSelfMsg(msg); 96 | 97 | } 98 | 99 | } 100 | 101 | 102 | /** @brief Cleanup*/ 103 | void AmacadWeightCluster::finish() { 104 | 105 | if ( mChangeDestinationMessage->isScheduled() ) 106 | cancelEvent( mChangeDestinationMessage ); 107 | delete mChangeDestinationMessage; 108 | MdmacNetworkLayer::finish(); 109 | 110 | } 111 | 112 | 113 | /** 114 | * Get the destination from the destination file. 115 | */ 116 | void AmacadWeightCluster::GetDestinationList() { 117 | 118 | mDestinationSet.clear(); 119 | 120 | std::ifstream inputStream; 121 | inputStream.open( par("destinationFile").stringValue() ); 122 | if ( inputStream.fail() ) 123 | throw cRuntimeError( "Cannot load the destination file." ); 124 | 125 | 126 | TraCIMobility *mob = dynamic_cast(mMobility); 127 | std::string carName, myName = mob->getExternalId(); 128 | int count; 129 | DestinationEntry e; 130 | int entryCount; 131 | bool save; 132 | 133 | inputStream >> entryCount; 134 | for ( int i = 0; i < entryCount; i++ ) { 135 | 136 | inputStream >> carName >> count; 137 | save = ( carName == myName ); 138 | for ( int j = 0; j < count; j++ ) { 139 | 140 | inputStream >> e.mTime >> e.mDestination.x >> e.mDestination.y; 141 | if ( save ) 142 | mDestinationSet.push_back( e ); 143 | 144 | } 145 | 146 | if ( save ) 147 | break; 148 | 149 | } 150 | 151 | inputStream.close(); 152 | 153 | } 154 | 155 | 156 | 157 | /** Add the destination data to a packet. */ 158 | int AmacadWeightCluster::AddDestinationData( MdmacControlMessage *pkt ) { 159 | 160 | pkt->setXDestination( mCurrentDestination.x ); 161 | pkt->setYDestination( mCurrentDestination.y ); 162 | return 128; 163 | 164 | } 165 | 166 | 167 | 168 | /** Store the destination data from a packet. */ 169 | void AmacadWeightCluster::StoreDestinationData( MdmacControlMessage *m ) { 170 | 171 | mNeighbours[m->getNodeId()].mDestination.x = m->getXDestination(); 172 | mNeighbours[m->getNodeId()].mDestination.y = m->getYDestination(); 173 | 174 | } 175 | 176 | 177 | /** @brief Compute the CH weight for this node. */ 178 | double AmacadWeightCluster::calculateWeight() { 179 | 180 | if ( !mMobility || mNeighbours.size() == 0 ) 181 | return -DBL_MAX; 182 | 183 | Coord p = mMobility->getCurrentPosition(); 184 | Coord v = mMobility->getCurrentSpeed(); 185 | 186 | double dL, dS, dD, ret = 0; 187 | for ( NeighbourIterator it = mNeighbours.begin(); it != mNeighbours.end(); it++ ) { 188 | dL = ( p - it->second.mPosition ).length(); 189 | dS = ( v - it->second.mVelocity ).length(); 190 | dD = ( mCurrentDestination - it->second.mDestination ).length(); 191 | ret += dL * mWeights[0] + dS * mWeights[1] + dD * mWeights[2]; 192 | } 193 | 194 | return -ret; 195 | 196 | } 197 | -------------------------------------------------------------------------------- /src/AmacadWeightCluster.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef __CLUSTERLIB_AMACADWEIGHTCLUSTER_H_ 17 | #define __CLUSTERLIB_AMACADWEIGHTCLUSTER_H_ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include "MdmacControlMessage_m.h" 28 | #include "MdmacNetworkLayer.h" 29 | 30 | 31 | /** 32 | * Implements the Lane-Sense Utility Function (LSUF) Clustering metric. 33 | */ 34 | class AmacadWeightCluster : public MdmacNetworkLayer 35 | { 36 | public: 37 | /** @brief Initialization of the module and some variables*/ 38 | virtual void initialize(int); 39 | 40 | /** @brief Handle self messages */ 41 | virtual void handleSelfMsg(cMessage* msg); 42 | 43 | /** @brief Cleanup*/ 44 | void finish(); 45 | 46 | protected: 47 | 48 | /** Get the destination from the destination file. */ 49 | void GetDestinationList(); 50 | 51 | struct DestinationEntry { 52 | double mTime; /**< The time until which this is our destination. */ 53 | Coord mDestination; /**< The coordinates of this destination. */ 54 | }; 55 | 56 | typedef std::vector DestinationSet; 57 | 58 | double mWeights[3]; /**< Set of weights. */ 59 | DestinationSet mDestinationSet; /**< Set of destinations. */ 60 | cMessage *mChangeDestinationMessage; /**< Message to change the destination. */ 61 | Coord mCurrentDestination; /**< Current destination of the node. */ 62 | 63 | 64 | /** Add the destination data to a packet. */ 65 | int AddDestinationData( MdmacControlMessage *pkt ); 66 | 67 | /** Store the destination data from a packet. */ 68 | void StoreDestinationData( MdmacControlMessage *m ); 69 | 70 | 71 | /** @brief Compute the CH weight for this node. */ 72 | double calculateWeight(); 73 | }; 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /src/AmacadWeightCluster.ned: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | package clusterlib; 17 | 18 | // 19 | // Implements the Lane-Sense Utility Function (LSUF) Clustering metric. 20 | // 21 | simple AmacadWeightCluster extends MdmacNetworkLayer 22 | { 23 | parameters: 24 | @class(AmacadWeightCluster); 25 | double distanceWeight; 26 | double speedWeight; 27 | double destinationWeight; 28 | string destinationFile; 29 | } 30 | -------------------------------------------------------------------------------- /src/ClusterAlgorithm.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * ClusterAlgorithm.cc 3 | * 4 | * Created on: Aug 20, 2013 5 | * Author: craig 6 | */ 7 | 8 | #include 9 | #include "ClusterAlgorithm.h" 10 | 11 | 12 | 13 | ClusterAlgorithm::ClusterAlgorithm() : BaseNetwLayer() { 14 | // TODO Auto-generated constructor stub 15 | 16 | } 17 | 18 | ClusterAlgorithm::~ClusterAlgorithm() { 19 | // TODO Auto-generated destructor stub 20 | } 21 | 22 | 23 | 24 | 25 | void ClusterAlgorithm::ClusterStarted() { 26 | 27 | mCurrentMaximumClusterSize = mClusterMembers.size(); 28 | mClusterStartTime = simTime(); 29 | // std::cerr << mId << ": Cluster Started!\n"; 30 | 31 | } 32 | 33 | 34 | 35 | void ClusterAlgorithm::ClusterMemberAdded( int id ) { 36 | 37 | mClusterMembers.insert( id ); 38 | mCurrentMaximumClusterSize = std::max( (int)mCurrentMaximumClusterSize, (int)mClusterMembers.size() ); 39 | 40 | } 41 | 42 | 43 | 44 | void ClusterAlgorithm::ClusterMemberRemoved( int id ) { 45 | 46 | mClusterMembers.erase(id); 47 | if ( mClusterMembers.size() == GetMinimumClusterSize() ) { 48 | mCurrentMaximumClusterSize += 1; 49 | // std::cerr << "Cluster died of attrition! |C|=" << mCurrentMaximumClusterSize << "\n"; 50 | ClusterDied( CD_Attrition ); 51 | } 52 | 53 | } 54 | 55 | 56 | 57 | void ClusterAlgorithm::ClusterDied( int deathType ) { 58 | 59 | Coord pos = mMobility->getCurrentPosition(); 60 | if ( simTime() - mClusterStartTime > 2 ) { 61 | // std::cerr << mId << ": Cluster died! L = " << simTime() - mClusterStartTime << "; S = " << mCurrentMaximumClusterSize << "\n"; 62 | // std::cerr << "STUB! " << simTime() - mClusterStartTime << " " << mCurrentMaximumClusterSize << "\n"; 63 | emit( mSigClusterLifetime, simTime() - mClusterStartTime ); 64 | emit( mSigClusterSize, (double)mCurrentMaximumClusterSize ); 65 | emit( mSigClusterDeathType, (double)deathType ); 66 | emit( mSigClusterDeathX, pos.x ); 67 | emit( mSigClusterDeathY, pos.y ); 68 | } 69 | 70 | mCurrentMaximumClusterSize = 0; 71 | mClusterStartTime = 0; 72 | 73 | } 74 | 75 | 76 | 77 | int ClusterAlgorithm::GetMaximumClusterSize() { 78 | return mCurrentMaximumClusterSize; 79 | } 80 | 81 | 82 | 83 | 84 | int ClusterAlgorithm::GetClusterHead() { 85 | return mClusterHead; 86 | } 87 | 88 | 89 | bool ClusterAlgorithm::NodeIsMember( unsigned int nodeId ) { 90 | return mClusterMembers.find( nodeId ) != mClusterMembers.end(); 91 | } 92 | 93 | 94 | void ClusterAlgorithm::GetClusterMemberList( NodeIdSet *cm ) { 95 | NodeIdSet::iterator it = mClusterMembers.begin(); 96 | for ( ; it != mClusterMembers.end(); it++ ) 97 | cm->insert( *it ); 98 | } 99 | 100 | 101 | BaseMobility *ClusterAlgorithm::GetMobilityModule() { 102 | return mMobility; 103 | } 104 | 105 | 106 | 107 | /** @brief Initialization of the module and some variables*/ 108 | void ClusterAlgorithm::initialize( int state ) { 109 | 110 | BaseNetwLayer::initialize( state ); 111 | mCurrentMaximumClusterSize = 0; 112 | 113 | if ( state == 0 ) { 114 | 115 | // set up result connection 116 | mSigOverhead = registerSignal( "sigOverhead" ); 117 | mSigHelloOverhead = registerSignal( "sigHelloOverhead" ); 118 | mSigClusterLifetime = registerSignal( "sigClusterLifetime" ); 119 | mSigClusterSize = registerSignal( "sigClusterSize" ); 120 | mSigHeadChange = registerSignal( "sigHeadChange" ); 121 | 122 | mSigClusterDeathType = registerSignal( "sigDeathType" ); 123 | mSigClusterDeathX = registerSignal( "sigDeathX" ); 124 | mSigClusterDeathY = registerSignal( "sigDeathY" ); 125 | 126 | } 127 | 128 | } 129 | 130 | /** @brief Cleanup*/ 131 | void ClusterAlgorithm::finish() { 132 | BaseNetwLayer::finish(); 133 | } 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /src/ClusterAlgorithm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ClusterAlgorithm.h 3 | * 4 | * Created on: Aug 20, 2013 5 | * Author: craig 6 | */ 7 | 8 | #ifndef CLUSTERALGORITHM_H_ 9 | #define CLUSTERALGORITHM_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | 19 | class ClusterAlgorithm : public BaseNetwLayer { 20 | public: 21 | 22 | /** 23 | * @brief Types of cluster death. 24 | */ 25 | enum ClusterDeath { 26 | CD_Attrition = 0, 27 | CD_Cannibal, 28 | CD_Suicide 29 | }; 30 | 31 | ClusterAlgorithm(); 32 | virtual ~ClusterAlgorithm(); 33 | 34 | typedef std::pair NodePair; 35 | typedef std::set NodeIdSet; 36 | typedef std::vector NodeIdList; 37 | 38 | virtual int GetStateCount() = 0; 39 | virtual int GetClusterState() = 0; 40 | virtual bool IsClusterHead() = 0; 41 | virtual bool IsSubclusterHead() = 0; 42 | virtual bool IsHierarchical() = 0; 43 | virtual int GetMinimumClusterSize() = 0; 44 | 45 | virtual void UpdateMessageString() = 0; 46 | 47 | virtual void ClusterStarted(); 48 | virtual void ClusterMemberAdded( int id ); 49 | virtual void ClusterMemberRemoved( int id ); 50 | virtual void ClusterDied( int deathType ); 51 | 52 | int GetMaximumClusterSize(); 53 | 54 | virtual int GetClusterHead(); 55 | virtual bool NodeIsMember( unsigned int ); 56 | virtual void GetClusterMemberList( NodeIdSet* ); 57 | virtual BaseMobility *GetMobilityModule(); 58 | 59 | std::string &GetMessageString() { return mMessageString; } 60 | 61 | /** @brief Initialization of the module and some variables*/ 62 | virtual void initialize(int); 63 | 64 | /** @brief Cleanup*/ 65 | virtual void finish(); 66 | 67 | /** 68 | * @name Results 69 | * @brief Results to be recorded. 70 | * 71 | * These members record the performance of the algorithm. 72 | * The following performance metrics are recorded: 73 | * 1. Overhead per node: 74 | * This is the amount of traffic dedicated to cluster control, 75 | * measured as total bytes transmitted. 76 | * Type: Scalar 77 | * 2. Overhead per node (HELLO messages only): 78 | * This is the amount of traffic dedicated HELLO messages, 79 | * measured as total bytes transmitted. 80 | * Type: Scalar 81 | * 3. Cluster Lifetime: 82 | * A cluster's life begins when a node becomes a CH and obtains 83 | * its first CM. It dies either when the CH becomes a CM of another 84 | * cluster, or the CH loses all its members. The lifetime is the 85 | * time, in seconds, between each of these events. 86 | * Type: Scalar 87 | * 4. Cluster Size: 88 | * Larger clusters mean more stability and lighter load on RSU 89 | * Backbone. 90 | * Type: Scalar 91 | * 5. CH changes per node: 92 | * How often do CMs change CH? 93 | * Type: Scalar 94 | * 95 | **/ 96 | /*@{*/ 97 | 98 | simsignal_t mSigOverhead; /**< Overhead per node (not including HELLO messages). */ 99 | simsignal_t mSigHelloOverhead; /**< Overhead per node (HELLO messages only). */ 100 | simsignal_t mSigClusterLifetime; /**< Lifetime of a cluster for which this node is CH. */ 101 | simsignal_t mSigClusterSize; /**< Size of the cluster for which this node is CH. */ 102 | simsignal_t mSigHeadChange; /**< Changes in CH for this node. */ 103 | 104 | simsignal_t mSigClusterDeathType; /**< Type of cluster death this node goes through. */ 105 | simsignal_t mSigClusterDeathX; /**< X position of cluster deaths. */ 106 | simsignal_t mSigClusterDeathY; /**< Y position of cluster deaths. */ 107 | 108 | 109 | /*@}*/ 110 | 111 | protected: 112 | unsigned int mId; /**< ID of the node. */ 113 | int mClusterHead; /**< ID of the CH we're associated with (initialised to -1). */ 114 | NodeIdSet mClusterMembers; /**< Set of CMs associated with this node (if it is a CH) */ 115 | BaseMobility *mMobility; /**< Mobility module for this node. */ 116 | 117 | simtime_t mClusterStartTime; /**< The time at which this node last became a CH. */ 118 | int mCurrentMaximumClusterSize; /**< The highest number of nodes in the cluster of which we are currently head. */ 119 | 120 | std::string mMessageString; /**< Message to show in visualiser. */ 121 | 122 | }; 123 | 124 | #endif /* CLUSTERALGORITHM_H_ */ 125 | -------------------------------------------------------------------------------- /src/ClusterAnalysisScenarioManager.cc: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #include "ClusterAnalysisScenarioManager.h" 17 | 18 | #ifndef NDEBUG 19 | #include 20 | #include "ChannelAccess.h" 21 | #include "ClusterAlgorithm.h" 22 | #endif 23 | 24 | Define_Module(ClusterAnalysisScenarioManager); 25 | 26 | 27 | ClusterAnalysisScenarioManager::ClusterAnalysisScenarioManager() { 28 | // TODO Auto-generated constructor stub 29 | 30 | } 31 | 32 | ClusterAnalysisScenarioManager::~ClusterAnalysisScenarioManager() { 33 | // TODO Auto-generated destructor stub 34 | } 35 | 36 | 37 | 38 | void ClusterAnalysisScenarioManager::joinMessageSent( int srcId, int destId, bool isAck ) { 39 | 40 | if ( isAck ) 41 | mAffiliationAckRecord[ SrcDestPair(srcId,destId) ] = simTime().dbl(); 42 | else 43 | mAffiliationRecord[ SrcDestPair(srcId,destId) ] = simTime().dbl(); 44 | 45 | } 46 | 47 | 48 | void ClusterAnalysisScenarioManager::joinMessageReceived( int srcId, int destId, bool isAck ) { 49 | 50 | if ( isAck ) { 51 | mAffiliationAckRecord.erase( SrcDestPair(srcId,destId) ); 52 | //std::cerr << "Fault Ack removed " << srcId << "," << destId << "\n"; 53 | } else { 54 | mAffiliationRecord.erase( SrcDestPair(srcId,destId) ); 55 | } 56 | 57 | } 58 | 59 | 60 | void ClusterAnalysisScenarioManager::initialize(int stage) { 61 | 62 | if ( stage == 0 ) { 63 | 64 | #ifndef NDEBUG 65 | // setup the visualiser 66 | mVisualiser = par( "visualiser" ).boolValue(); 67 | if ( mVisualiser ) { 68 | mScreenDimensions.x = par( "displayWidth" ).longValue(); 69 | mScreenDimensions.y = par( "displayHeight" ).longValue(); 70 | mFramePeriod = 1 / par( "framesPerSecond" ).doubleValue(); 71 | Coord areaDims; 72 | areaDims.x = par( "playgroundSizeX" ).longValue(); 73 | areaDims.y = par( "playgroundSizeY" ).longValue(); 74 | mDrawer = new ClusterDraw( mScreenDimensions, areaDims ); 75 | if ( !mDrawer ) 76 | opp_error( "Could not create drawer object." ); 77 | 78 | mUpdateMessage = new cMessage; 79 | scheduleAt( simTime() + mFramePeriod, mUpdateMessage ); 80 | } 81 | #endif 82 | 83 | // Load the parameters of the simulation and generate the maps. 84 | std::string simType = par("simType").stringValue(); 85 | if ( simType == "highway" ) 86 | mType = Highway; 87 | else if ( simType == "grid" ) 88 | mType = Grid; 89 | else 90 | opp_error( "Unknown simulation type '%s'!", simType.c_str() ); 91 | 92 | char cmd[2000]; 93 | int seed = par("seed"); 94 | mRunPrefix = par("filePrefix").stdstringValue(); 95 | mNodeDensity = par("nodeDensity").doubleValue(); 96 | 97 | if ( mType == Highway ) { 98 | 99 | mJunctionCount = par("junctionCount").longValue(); 100 | mLaneCount = par("laneCount").longValue(); 101 | mCarSpeed = par("carSpeed").longValue(); 102 | mCarSpeedVariance = par("carSpeedVariance").doubleValue(); 103 | mTurnProbability = par("turnProbability").doubleValue(); 104 | 105 | // Generate the maps. 106 | sprintf( cmd, "python ./scripts/GenerateGrid.py -d $(pwd)/maps/ -j %d -J %d -L %d -l %d -a %d -A %d -v %f -y %f -m %f -M %f -b %f -V $(pwd)/%s -S %d -t %d -w %f -p $(pwd)/scripts/ -c $(pwd)/scripts/ %s -q %i -B %s > %s.router.log", 107 | mJunctionCount, mJunctionCount, 108 | mLaneCount, mLaneCount, 109 | mCarSpeed, mCarSpeed, 110 | mNodeDensity, mNodeDensity, 111 | mCarSpeedVariance, mCarSpeedVariance, 112 | mTurnProbability, 113 | (const char*)par("carDefFile").stringValue(), 114 | par("warmupTime").longValue(), 115 | par("simulationTime").longValue(), 116 | par("laneWidth").doubleValue(), 117 | ( mType == Highway ? "-H" : "" ), 118 | seed, 119 | mRunPrefix.c_str(), 120 | mRunPrefix.c_str() ); 121 | 122 | } else if ( mType == Grid ) { 123 | 124 | // Get configurations 125 | mBaseMap = par("baseMap").stdstringValue(); 126 | mNumberOfCBDs = par("cbdCount").longValue(); 127 | 128 | // Generate SUMO config file. 129 | std::ofstream outputStream; 130 | outputStream.open( ( std::string("./maps/") + mRunPrefix+".sumo.cfg" ).c_str() ); 131 | outputStream << "\n"; 132 | outputStream << "\n"; 133 | outputStream << "\t\n"; 134 | outputStream << "\t\t\n"; 135 | outputStream << "\t\t\n"; 136 | outputStream << "\t\n"; 137 | outputStream << "\t\n"; 142 | outputStream << "\n"; 143 | outputStream.close(); 144 | 145 | // Generate the maps. 146 | sprintf( cmd, "python ./scripts/gridRouter.py -n $(pwd)/maps/%s.net.xml -o $(pwd)/maps/%s.rou.xml -v %s -N %f -u -1 -c %d -r %d -s %d > %s.router.log", 147 | mBaseMap.c_str(), 148 | mRunPrefix.c_str(), 149 | (const char*)par("carDefFile").stringValue(), 150 | mNodeDensity, 151 | mNumberOfCBDs, 152 | par("simulationTime").longValue(), 153 | seed, 154 | mRunPrefix.c_str() ); 155 | 156 | // mCheckAffiliationRecord = new cMessage(); 157 | // scheduleAt( simTime()+1, mCheckAffiliationRecord ); 158 | // mSigFaultAffiliation = registerSignal( "sigFaultAffiliation" ); 159 | // 160 | // UraeScenarioManager::initialize(stage); 161 | // return; 162 | 163 | } 164 | 165 | std::cerr << "Executing command: " << std::endl << cmd << std::endl; 166 | system(cmd); 167 | 168 | mSimulationTime = par("simulationTime").longValue(); 169 | 170 | mCheckAffiliationRecord = new cMessage(); 171 | scheduleAt( simTime()+1, mCheckAffiliationRecord ); 172 | mSigFaultAffiliation = registerSignal( "sigFaultAffiliation" ); 173 | mSigFaultAffiliationAck = registerSignal( "sigFaultAffiliationAck" ); 174 | 175 | } 176 | UraeScenarioManager::initialize(stage); 177 | 178 | } 179 | 180 | 181 | void ClusterAnalysisScenarioManager::handleSelfMsg( cMessage *m ) { 182 | 183 | if ( m == mCheckAffiliationRecord ) { 184 | 185 | // Check the Affiliation record. 186 | std::vector pairsToErase; 187 | for ( AffiliationMap::iterator it = mAffiliationRecord.begin(); it != mAffiliationRecord.end(); it++ ) { 188 | if ( fabs( it->second - simTime().dbl() ) > 1 ) { 189 | emit( mSigFaultAffiliation, 1 ); 190 | pairsToErase.push_back( it->first ); 191 | } 192 | } 193 | 194 | for ( std::vector::iterator it = pairsToErase.begin(); it != pairsToErase.end(); it++ ) 195 | mAffiliationRecord.erase( *it ); 196 | 197 | // Check the Affiliation Acknowledgement record. 198 | pairsToErase.clear(); 199 | for ( AffiliationMap::iterator it = mAffiliationAckRecord.begin(); it != mAffiliationAckRecord.end(); it++ ) { 200 | if ( fabs( it->second - simTime().dbl() ) > 1 ) { 201 | emit( mSigFaultAffiliationAck, 1 ); 202 | //std::cerr << "Fault Ack: " << it->first.first << " to " << it->first.second << "\n"; 203 | pairsToErase.push_back( it->first ); 204 | } 205 | } 206 | 207 | for ( std::vector::iterator it = pairsToErase.begin(); it != pairsToErase.end(); it++ ) 208 | mAffiliationAckRecord.erase( *it ); 209 | 210 | scheduleAt( simTime()+1, mCheckAffiliationRecord ); 211 | 212 | #ifndef NDEBUG 213 | } else if ( mVisualiser && m == mUpdateMessage ) { 214 | 215 | for ( std::map::iterator it = hosts.begin(); it != hosts.end(); it++ ) { 216 | 217 | cModule *clusterAlgorithm = it->second->getSubmodule("net",-1); 218 | ClusterAlgorithm *mod = dynamic_cast(clusterAlgorithm); 219 | if ( !mod ) 220 | continue; 221 | 222 | BaseMobility *mob = dynamic_cast(it->second->getSubmodule("mobility",-1)); 223 | if ( !mob ) 224 | continue; 225 | 226 | ClusterDraw::Colour col; 227 | bool isHead = mod->IsClusterHead(); 228 | int currState = mod->GetClusterState(); 229 | 230 | if ( mClusterStateColours.empty() ) 231 | for ( int i = 0; i < mod->GetStateCount(); i++ ) 232 | mClusterStateColours.push_back( ClusterDraw::Colour( rand() / (float)RAND_MAX, rand() / (float)RAND_MAX, rand() / (float)RAND_MAX ) ); 233 | 234 | col = mClusterStateColours[currState]; 235 | 236 | Coord pos = mob->getCurrentPosition(); 237 | if ( isHead ) { 238 | 239 | mDrawer->drawCircle( pos, 2, col, 3 ); 240 | if ( mod->IsSubclusterHead() ) { 241 | ClusterAlgorithm *p = dynamic_cast( cSimulation::getActiveSimulation()->getModule( mod->GetClusterHead() ) ); 242 | if ( p && p != mod ) { 243 | float w; 244 | col = ClusterDraw::Colour(1,0,1); 245 | if ( p->NodeIsMember( mod->getId() ) ) { 246 | col = ClusterDraw::Colour(0,0,0); 247 | w = 2.5; 248 | } else { 249 | mDrawer->drawCircle( pos, 4, col ); 250 | w = 1; 251 | } 252 | mDrawer->drawLine( pos, p->GetMobilityModule()->getCurrentPosition(), col, w ); 253 | } 254 | } 255 | 256 | // Draw lines to nodes this node thinks are part of it's cluster. 257 | ClusterAlgorithm::NodeIdSet n; 258 | mod->GetClusterMemberList(&n); 259 | for ( ClusterAlgorithm::NodeIdSet::iterator it = n.begin(); it != n.end(); it++ ) { 260 | ClusterAlgorithm *p = dynamic_cast( cSimulation::getActiveSimulation()->getModule( *it ) ); 261 | if ( p && p->GetClusterHead() != mod->getId() ) 262 | mDrawer->drawLine( pos, p->GetMobilityModule()->getCurrentPosition(), ClusterDraw::Colour(1,0,0), 2 ); 263 | } 264 | 265 | // mDrawer->drawString( pos + Coord(0,6), mod->GetMessageString(), ClusterDraw::Colour(0,0,0) ); 266 | 267 | } else { 268 | 269 | mDrawer->drawCircle( pos, 2, col ); 270 | ClusterAlgorithm *p = dynamic_cast( cSimulation::getActiveSimulation()->getModule( mod->GetClusterHead() ) ); 271 | if ( p && p != mod ) { 272 | float w; 273 | col = ClusterDraw::Colour(1,0,1); 274 | if ( p->NodeIsMember( mod->getId() ) ) { 275 | col = ClusterDraw::Colour(0,0,0); 276 | w = 2.5; 277 | } else { 278 | mDrawer->drawCircle( pos, 4, col ); 279 | w = 1; 280 | } 281 | mDrawer->drawLine( pos, p->GetMobilityModule()->getCurrentPosition(), col, w ); 282 | } 283 | 284 | } 285 | 286 | mDrawer->drawString( pos + Coord(0,6), mod->GetMessageString(), ClusterDraw::Colour(0,0,0) ); 287 | 288 | // ChannelAccess *channelAccess = FindModule::findSubModule(it->second); 289 | // float radius = channelAccess->getConnectionManager( channelAccess->getParentModule() )->getMaxInterferenceDistance(); 290 | // mDrawer->drawCircle( pos, radius, ClusterDraw::Colour(0,0,0) ); 291 | 292 | } 293 | mDrawer->update( mFramePeriod ); 294 | scheduleAt( simTime() + mFramePeriod, mUpdateMessage ); 295 | 296 | #endif 297 | 298 | } else { 299 | 300 | UraeScenarioManager::handleSelfMsg( m ); 301 | 302 | } 303 | 304 | } 305 | 306 | 307 | void ClusterAnalysisScenarioManager::finish() { 308 | 309 | // clean up all the files, except the launchd file, which needs to be preserved 310 | std::string cmdBase = std::string( "rm ./maps/" ) + mRunPrefix; 311 | std::string cmd; 312 | 313 | cmd = cmdBase + ".net.*"; 314 | system( cmd.c_str() ); 315 | 316 | cmd = cmdBase + ".rou*"; 317 | system( cmd.c_str() ); 318 | 319 | cmd = cmdBase + ".corner*"; 320 | system( cmd.c_str() ); 321 | 322 | cmd = cmdBase + ".lsuf"; 323 | system( cmd.c_str() ); 324 | 325 | cmd = cmdBase + ".sumo*"; 326 | system( cmd.c_str() ); 327 | 328 | if ( mCheckAffiliationRecord->isScheduled() ) 329 | cancelEvent( mCheckAffiliationRecord ); 330 | delete mCheckAffiliationRecord; 331 | 332 | #ifndef NDEBUG 333 | if ( mVisualiser ) { 334 | if ( mUpdateMessage->isScheduled() ) 335 | cancelEvent( mUpdateMessage ); 336 | delete mUpdateMessage; 337 | if ( mDrawer ) 338 | delete mDrawer; 339 | } 340 | #endif 341 | 342 | UraeScenarioManager::finish(); 343 | 344 | } 345 | 346 | 347 | 348 | 349 | inline bool fileExists(const char *filename) { 350 | ifstream f(filename); 351 | if (f.good()) { 352 | f.close(); 353 | return true; 354 | } else { 355 | f.close(); 356 | return false; 357 | } 358 | } 359 | 360 | 361 | 362 | 363 | 364 | -------------------------------------------------------------------------------- /src/ClusterAnalysisScenarioManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef CLUSTERANALYSISSCENARIOMANAGER_H_ 17 | #define CLUSTERANALYSISSCENARIOMANAGER_H_ 18 | 19 | #include 20 | 21 | #ifndef NDEBUG 22 | #include "ClusterDraw.h" 23 | #endif 24 | 25 | 26 | class ClusterAnalysisScenarioManager: public UraeScenarioManager { 27 | 28 | public: 29 | ClusterAnalysisScenarioManager(); 30 | virtual ~ClusterAnalysisScenarioManager(); 31 | 32 | void joinMessageSent( int srcId, int destId, bool isAck = false ); 33 | void joinMessageReceived( int srcId, int destId, bool isAck = false ); 34 | 35 | virtual void initialize(int stage); 36 | virtual void handleSelfMsg( cMessage *m ); 37 | virtual void finish(); 38 | 39 | double getSimulationTime() { return mSimulationTime; } 40 | 41 | private: 42 | typedef std::pair SrcDestPair; 43 | typedef std::map AffiliationMap; 44 | 45 | AffiliationMap mAffiliationRecord; 46 | AffiliationMap mAffiliationAckRecord; // We need to check if an ACK was properly received upon affiliation 47 | cMessage *mCheckAffiliationRecord; 48 | simsignal_t mSigFaultAffiliation; 49 | simsignal_t mSigFaultAffiliationAck; 50 | 51 | // simulation parameters 52 | enum SimulationType { 53 | Highway = 0, 54 | Grid 55 | }; 56 | 57 | SimulationType mType; 58 | std::string mRunPrefix; 59 | double mNodeDensity; // Node density is common to both simulation types. 60 | double mSimulationTime; // Simulation Time 61 | 62 | // Highway simulations. 63 | int mJunctionCount; 64 | int mLaneCount; 65 | int mCarSpeed; 66 | double mCarSpeedVariance; 67 | double mTurnProbability; 68 | 69 | // Grid simulations 70 | std::string mBaseMap; 71 | int mNumberOfCBDs; 72 | 73 | #ifndef NDEBUG 74 | bool mVisualiser; 75 | ClusterDraw *mDrawer; 76 | Coord mScreenDimensions; 77 | double mFramePeriod; 78 | cMessage *mUpdateMessage; 79 | std::vector mClusterStateColours; 80 | #endif 81 | 82 | }; 83 | 84 | 85 | 86 | class ClusterAnalysisScenarioManagerAccess 87 | { 88 | public: 89 | static ClusterAnalysisScenarioManager* get() { 90 | return FindModule::findGlobalModule(); 91 | }; 92 | }; 93 | 94 | 95 | inline bool fileExists(const char *filename); 96 | 97 | #endif /* CLUSTERANALYSISSCENARIOMANAGER_H_ */ 98 | -------------------------------------------------------------------------------- /src/ClusterAnalysisScenarioManager.ned: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | package clusterlib; 17 | 18 | // 19 | // TODO auto-generated type 20 | // 21 | package org.mixim.modules.mobility.traci; 22 | 23 | 24 | simple ClusterAnalysisScenarioManager 25 | { 26 | parameters: 27 | @display("i=block/cogwheel"); 28 | bool debug = default(false); // emit debug messages? 29 | double connectAt @unit("s") = default(0s); // when to connect to TraCI server (must be the initial timestep of the server) 30 | double firstStepAt @unit("s") = default(-1s); // when to start synchronizing with the TraCI server (-1: immediately after connecting) 31 | double updateInterval @unit("s") = default(1s); // time interval of hosts' position updates 32 | string moduleType = default("inet.nodes.wireless.WirelessHostSimplified"); // module type to be used in the simulation for each managed vehicle 33 | string moduleName = default("host"); // module name to be used in the simulation for each managed vehicle 34 | string moduleDisplayString = default("i=misc/node2;is=vs;r=0,,#707070,1"); // module displayString to be used in the simulation for each managed vehicle 35 | string host = default("localhost"); // TraCI server hostname 36 | int port = default(9999); // TraCI server port 37 | xml launchConfig = default( xmldoc("maps/simFile.launchd.xml") ); // launch configuration to send to sumo-launchd 38 | int seed = default(-1); // seed value to set in launch configuration, if missing (-1: current run number) 39 | bool autoShutdown = default(true); // Shutdown module as soon as no more vehicles are in the simulation 40 | int margin = default(25); // margin to add to all received vehicle positions 41 | string roiRoads = default(""); // which roads (e.g. "hwy1 hwy2") are considered to consitute the region of interest, if not empty 42 | string roiRects = default(""); // which rectangles (e.g. "0,0-10,10 20,20-30,30) are considered to consitute the region of interest, if not empty 43 | double penetrationRate = default(1); //the probability of a vehicle being equipped with Car2X technology 44 | 45 | @statistic[faultAffiliation]( source = "count(sigFaultAffiliation)"; record = last; title = "Fault Affiliations"; ); 46 | @statistic[faultAffiliationAck]( source = "count(sigFaultAffiliationAck)"; record = last; title = "Fault Affiliation Acknowledgements"; ); 47 | 48 | // Urae stuff 49 | string linksFile = default(""); 50 | string nodesFile = default(""); 51 | string classFile = default(""); 52 | string linkMapFile = default(""); 53 | string intLinkMapFile = default(""); 54 | string riceFile = default(""); 55 | string carDefFile = default(""); 56 | double laneWidth @unit("m") = default(2.5m); 57 | double waveLength @unit("m") = default(0.125m); 58 | double txPower @unit("mW") = default(80mW); 59 | double systemLoss = default(1142.9); // NOTE: This should be determined experimentally 60 | double sensitivity @unit("dBm") = default(-110dBm); 61 | double lossPerReflection = default(0.75); 62 | string componentFile = default("default.fading"); 63 | int randSeed = default(1234); 64 | int gridSize @unit("m") = default(200m); 65 | 66 | int simulationTime @unit(s) = default(3000s); 67 | int warmupTime @unit(s) = default(1000s); 68 | string simType = default("highway"); 69 | string filePrefix; 70 | double nodeDensity = default(2); 71 | 72 | // Highway simulations 73 | int junctionCount = default(0); 74 | int laneCount = default(1); 75 | int carSpeed @unit("kmph") = default(40kmph); 76 | double carSpeedVariance = default(0); 77 | double turnProbability = default(0.1); 78 | 79 | // Grid simulations. 80 | string baseMap; 81 | int cbdCount = default(1); 82 | 83 | // Graphics display stuff 84 | bool visualiser = default(false); 85 | double displayWidth = default(1280); 86 | double displayHeight = default(960); 87 | double framesPerSecond = default(1); 88 | int playgroundSizeX @unit("m"); 89 | int playgroundSizeY @unit("m"); 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/ClusterDraw.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * ClusterDraw.cpp 3 | * 4 | * Created on: Jun 18, 2013 5 | * Author: craig 6 | */ 7 | 8 | #ifndef NDEBUG 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "ClusterDraw.h" 16 | 17 | 18 | 19 | /** Default constructor */ 20 | ClusterDraw::ClusterDraw( Coord dims, Coord pgSize ) { 21 | 22 | al_init(); 23 | al_install_keyboard(); 24 | al_init_primitives_addon(); 25 | al_init_font_addon(); 26 | al_init_ttf_addon(); 27 | 28 | mDisplay = al_create_display( dims.x, dims.y ); 29 | mPlaygroundSize = pgSize; 30 | 31 | mScreenDimensions = dims; 32 | mCameraPosition = Coord(); 33 | mFieldOfView = M_PI / 4; 34 | mAspectRatio = dims.y / dims.x; 35 | mHeight = mCameraPosition.x / ( 2 * tan( mFieldOfView ) ); 36 | mHalfViewDimensions.x = mCameraPosition.x; 37 | mHalfViewDimensions.y = mAspectRatio * mCameraPosition.x; 38 | 39 | mTextFont = al_load_font( "ARIALUNI.TTF", 16, 0 ); 40 | 41 | mPrintStatus = false; 42 | 43 | } 44 | 45 | 46 | /** Default destructor */ 47 | ClusterDraw::~ClusterDraw() { 48 | 49 | al_destroy_display( mDisplay ); 50 | 51 | al_shutdown_primitives_addon(); 52 | al_uninstall_keyboard(); 53 | al_uninstall_system(); 54 | 55 | } 56 | 57 | 58 | 59 | 60 | 61 | /** Draw a circle. */ 62 | void ClusterDraw::drawCircle( Coord p, double r, Colour c, double weight, bool filled ) { 63 | 64 | Circle circle; 65 | circle.mOrigin = p; 66 | circle.mRadius = r; 67 | circle.mColour = c; 68 | circle.mWeight = weight; 69 | circle.mFilled = filled; 70 | mCircleList.push_back( circle ); 71 | 72 | } 73 | 74 | 75 | 76 | 77 | /** Draw a line. */ 78 | void ClusterDraw::drawLine( Coord p1, Coord p2, Colour c, double thickness ) { 79 | 80 | Line l; 81 | l.mStart = p1; 82 | l.mEnd = p2; 83 | l.mColour = c; 84 | l.mThickness = thickness; 85 | mLineList.push_back( l ); 86 | 87 | } 88 | 89 | 90 | 91 | /** Draw a string of text. */ 92 | void ClusterDraw::drawString( Coord p, std::string &s, Colour c ) { 93 | 94 | Text t; 95 | t.mPosition = p; 96 | t.mColour = c; 97 | t.mText = s; 98 | mTextList.push_back( t ); 99 | 100 | } 101 | 102 | 103 | 104 | 105 | /** Get the current camera height. */ 106 | double ClusterDraw::getCameraHeight() { 107 | 108 | return mHeight; 109 | 110 | } 111 | 112 | 113 | 114 | /** Set the current camera height. */ 115 | void ClusterDraw::setCameraHeight( double h ) { 116 | mHeight = h; 117 | } 118 | 119 | 120 | 121 | /** Update the view and flip the display. */ 122 | void ClusterDraw::update( double elapsedTime ) { 123 | 124 | bool heightChanged = false; 125 | ALLEGRO_KEYBOARD_STATE s; 126 | al_get_keyboard_state( &s ); 127 | 128 | if ( al_key_down( &s, ALLEGRO_KEY_DOWN ) ) { 129 | mCameraPosition.y += 100 * elapsedTime; 130 | } else if ( al_key_down( &s, ALLEGRO_KEY_UP ) ) { 131 | mCameraPosition.y -= 100 * elapsedTime; 132 | } 133 | 134 | if ( al_key_down( &s, ALLEGRO_KEY_RIGHT ) ) { 135 | mCameraPosition.x += 100 * elapsedTime; 136 | } else if ( al_key_down( &s, ALLEGRO_KEY_LEFT ) ) { 137 | mCameraPosition.x -= 100 * elapsedTime; 138 | } 139 | 140 | if ( al_key_down( &s, ALLEGRO_KEY_S ) ) { 141 | mHeight += 100 * elapsedTime; 142 | heightChanged = true; 143 | } else if ( al_key_down( &s, ALLEGRO_KEY_W ) ) { 144 | mHeight -= 100 * elapsedTime; 145 | heightChanged = true; 146 | } 147 | 148 | if ( al_key_down( &s, ALLEGRO_KEY_Q ) ) 149 | mPrintStatus = true; 150 | else if ( al_key_down( &s, ALLEGRO_KEY_E ) ) 151 | mPrintStatus = false; 152 | 153 | if ( mHeight < 1 ) 154 | mHeight = 1; 155 | 156 | // update the view 157 | if ( heightChanged ) { 158 | mHalfViewDimensions.x = mHeight * tan( mFieldOfView ); 159 | mHalfViewDimensions.y = mAspectRatio * mHalfViewDimensions.x; 160 | } 161 | 162 | Coord topLeft = mCameraPosition - mHalfViewDimensions; 163 | Coord bottomRight = mCameraPosition + mHalfViewDimensions; 164 | 165 | if ( mHalfViewDimensions.x * 2 > mPlaygroundSize.x ) { 166 | mCameraPosition.x = mHalfViewDimensions.x; 167 | } else if ( bottomRight.x > mPlaygroundSize.x ) { 168 | mCameraPosition.x = mPlaygroundSize.x/2 - mHalfViewDimensions.x; 169 | } else if ( topLeft.x < 0 ) { 170 | mCameraPosition.x = mHalfViewDimensions.x; 171 | } 172 | 173 | if ( mHalfViewDimensions.y * 2 > mPlaygroundSize.y ) { 174 | mCameraPosition.y = mHalfViewDimensions.y; 175 | } else if ( bottomRight.y > mPlaygroundSize.y ) { 176 | mCameraPosition.y = mPlaygroundSize.y/2 - mHalfViewDimensions.y; 177 | } else if ( topLeft.y < 0 ) { 178 | mCameraPosition.y = mHalfViewDimensions.y; 179 | } 180 | 181 | topLeft = mCameraPosition - mHalfViewDimensions; 182 | Coord dims = mHalfViewDimensions * 2; 183 | double multiplier = mAspectRatio * mScreenDimensions.x * 0.5 / mHalfViewDimensions.y; 184 | 185 | #define OutsideScreen(p) ( p.x < 0 || p.y < 0 || p.x > mScreenDimensions.x || p.y > mScreenDimensions.y ) 186 | 187 | // clear the screen. 188 | al_clear_to_color( al_map_rgb_f(1,1,1) ); 189 | 190 | // Now iterate through all the lines, correct their positions, and draw them. 191 | for ( LineList::iterator lineIt = mLineList.begin(); lineIt != mLineList.end(); lineIt++ ) { 192 | 193 | // Transform the coordinates to screen. 194 | Coord newStart, newEnd; 195 | newStart = ( lineIt->mStart - topLeft ) * multiplier; 196 | newEnd = ( lineIt->mEnd - topLeft ) * multiplier; 197 | 198 | // Make sure we're on the screen 199 | if ( OutsideScreen( newStart ) && OutsideScreen( newEnd ) ) 200 | continue; // We're not on the screen, so skip drawing the line. 201 | 202 | al_draw_line( newStart.x, newStart.y, newEnd.x, newEnd.y, al_map_rgb_f( lineIt->mColour.r, lineIt->mColour.g, lineIt->mColour.b ), lineIt->mThickness ); 203 | 204 | } 205 | 206 | // Now iterate through all the circles, correct their positions, and draw them. 207 | for ( CircleList::iterator circleIt = mCircleList.begin(); circleIt != mCircleList.end(); circleIt++ ) { 208 | 209 | // Transform the coordinates to screen. 210 | Coord newOrigin; 211 | newOrigin = ( circleIt->mOrigin - topLeft ) * multiplier; 212 | 213 | // Make sure we're on the screen 214 | if ( OutsideScreen( newOrigin ) ) 215 | continue; // We're not on the screen, so skip drawing the circle. 216 | 217 | if ( circleIt->mFilled ) 218 | al_draw_filled_circle( newOrigin.x, newOrigin.y, circleIt->mRadius * multiplier, al_map_rgb_f( circleIt->mColour.r, circleIt->mColour.g, circleIt->mColour.b ) ); 219 | else 220 | al_draw_circle( newOrigin.x, newOrigin.y, circleIt->mRadius * multiplier, al_map_rgb_f( circleIt->mColour.r, circleIt->mColour.g, circleIt->mColour.b ), circleIt->mWeight ); 221 | 222 | } 223 | 224 | // Now iterate through all the text objects, correct their positions, and draw them. 225 | for ( TextList::iterator textIt = mTextList.begin(); textIt != mTextList.end(); textIt++ ) { 226 | 227 | // Transform the coordinates to screen. 228 | Coord newPos = ( textIt->mPosition - topLeft ) * multiplier; 229 | 230 | // Make sure we're on the screen 231 | if ( OutsideScreen( newPos ) ) 232 | continue; // We're not on the screen, so skip drawing the circle. 233 | 234 | al_draw_textf( mTextFont, al_map_rgb_f( textIt->mColour.r, textIt->mColour.g, textIt->mColour.b ), newPos.x, newPos.y, 0, textIt->mText.c_str() ); 235 | 236 | } 237 | 238 | if ( mPrintStatus ) 239 | printStatus(); 240 | 241 | al_flip_display(); 242 | 243 | mLineList.clear(); 244 | mCircleList.clear(); 245 | mTextList.clear(); 246 | 247 | } 248 | 249 | 250 | 251 | 252 | /** Print the position and height of the camera. */ 253 | void ClusterDraw::printStatus() { 254 | 255 | Coord topLeft = mCameraPosition - mHalfViewDimensions; 256 | double h = al_get_font_line_height( mTextFont )+2; 257 | double mul = mAspectRatio * mScreenDimensions.x * 0.5 / mHalfViewDimensions.y; 258 | al_draw_textf( mTextFont, al_map_rgb_f(0,0,0), 0, 0, 0, "Position: %f,%f", mCameraPosition.x, mCameraPosition.y ); 259 | al_draw_textf( mTextFont, al_map_rgb_f(0,0,0), 0, h, 0, "Height: %f", mHeight ); 260 | al_draw_textf( mTextFont, al_map_rgb_f(0,0,0), 0, 2*h, 0, "Half-view: %f,%f", mHalfViewDimensions.x, mHalfViewDimensions.y ); 261 | al_draw_textf( mTextFont, al_map_rgb_f(0,0,0), 0, 3*h, 0, "Multiplier: %f", mul ); 262 | al_draw_textf( mTextFont, al_map_rgb_f(0,0,0), 0, 4*h, 0, "top-left: %f,%f", topLeft.x, topLeft.y ); 263 | 264 | } 265 | 266 | 267 | #endif /* #ifndef NDEBUG */ 268 | -------------------------------------------------------------------------------- /src/ClusterDraw.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ClusterDraw.h 3 | * 4 | * Created on: Aug 13, 2013 5 | * Author: craig 6 | */ 7 | 8 | #ifndef CLUSTERDRAW_H_ 9 | #define CLUSTERDRAW_H_ 10 | 11 | #ifndef NDEBUG 12 | 13 | #include 14 | #include 15 | #include 16 | #include "BaseMobility.h" 17 | 18 | class ClusterDraw { 19 | 20 | public: 21 | 22 | struct Colour { 23 | Colour( float _r=0, float _g=0, float _b=0 ) : r(_r), g(_g), b(_b) {} 24 | float r, g, b; 25 | }; 26 | 27 | struct Line { 28 | Coord mStart, mEnd; /**< Start and end points. */ 29 | Colour mColour; /**< Colour of the line. */ 30 | double mThickness; /**< Thickness of the line. */ 31 | }; 32 | 33 | struct Circle { 34 | Coord mOrigin; /**< Centre of the circle. */ 35 | double mRadius; /**< Radius of the circle. */ 36 | Colour mColour; /**< Colour of the circle */ 37 | double mWeight; /**< Thickness of the line. */ 38 | bool mFilled; /**< Is the circle filled? */ 39 | }; 40 | 41 | struct Text { 42 | Coord mPosition; /**< Position of text. */ 43 | Colour mColour; /**< Colour of text. */ 44 | std::string mText; /**< String of text. */ 45 | }; 46 | 47 | typedef std::vector LineList; 48 | typedef std::vector CircleList; 49 | typedef std::vector TextList; 50 | 51 | /** Default constructor */ 52 | ClusterDraw( Coord dims, Coord pgSize ); 53 | 54 | /** Default destructor */ 55 | virtual ~ClusterDraw(); 56 | 57 | /** Draw a circle. */ 58 | void drawCircle( Coord p, double r, Colour c, double weight = 1, bool filled=false ); 59 | 60 | /** Draw a line. */ 61 | void drawLine( Coord p1, Coord p2, Colour c, double thickness = 1 ); 62 | 63 | /** Draw a string of text. */ 64 | void drawString( Coord p, std::string &s, Colour c ); 65 | 66 | /** Get the current camera height. */ 67 | double getCameraHeight(); 68 | 69 | /** Set the current camera height. */ 70 | void setCameraHeight( double h ); 71 | 72 | /** Update the view and flip the display. */ 73 | void update( double elapsedTime ); 74 | 75 | protected: 76 | ALLEGRO_DISPLAY *mDisplay; /**< Pointer to the Allegro display. */ 77 | ALLEGRO_FONT *mTextFont; /**< Font to use for drawing. */ 78 | 79 | LineList mLineList; /**< List of lines to draw. */ 80 | CircleList mCircleList; /**< List of circles to draw. */ 81 | TextList mTextList; /**< List of text objects to draw. */ 82 | 83 | Coord mScreenDimensions; /**< Dimensions of the display in pixels. */ 84 | Coord mPlaygroundSize; /**< Size of the display's playground. */ 85 | Coord mCameraPosition; /**< Location of the camera's centre point. */ 86 | double mFieldOfView; /**< Field of View */ 87 | double mAspectRatio; /**< Aspect ratio of display. */ 88 | Coord mHalfViewDimensions; /**< Coord containing half the width and height of the view. */ 89 | double mHeight; /**< Height of the camera above the playing field. */ 90 | 91 | bool mPrintStatus; /**< Print the status of the camera. */ 92 | 93 | /** Print the position and height of the camera. */ 94 | void printStatus(); 95 | 96 | }; 97 | 98 | #endif /* #ifndef NDEBUG */ 99 | 100 | #endif /* LSUFDATA_H_ */ 101 | -------------------------------------------------------------------------------- /src/ExtendedRmacControlMessage.msg: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | cplusplus {{ 17 | #include "NetwPkt_m.h" 18 | #include "RMACData.h" 19 | }} 20 | packet NetwPkt; 21 | 22 | 23 | class noncobject NeighbourEntrySet; 24 | class noncobject NeighbourIdSet; 25 | class noncobject Route; 26 | 27 | // 28 | // Describes the RMAC cluster control message. 29 | // Extends the NetwPkt, so this can be used to encapsulate 30 | // application layer packets as well. 31 | // 32 | packet ExtendedRmacControlMessage extends NetwPkt { 33 | 34 | int nodeId; // Identifier of the neighbour. 35 | double xPosition; // X-Position of the neighbour. 36 | double yPosition; // Y-Position of the neighbour. 37 | double xVelocity; // X-Velocity of the neighbour. 38 | double yVelocity; // Y-Velocity of the neighbour. 39 | bool isClusterHead; // Is this node a CH or CHM? 40 | int clusterHead; // ID of this node's CH. 41 | unsigned int connectionCount; // Number of connections this node has. 42 | NeighbourEntrySet neighbourTable; // Neighbour table of this node. 43 | NeighbourIdSet neighbourIdTable; // Set of IDs in neighbour table (used for CLUS_PRES frames). 44 | NeighbourIdSet clusterHierarchy; // Sequence of cluster heads (used to prevent cyclical clusters). 45 | Route nodeRoute; // The route this node will take. 46 | int proposedRole; // Proposed role of this node (used for CLUS_UNIFY_REQ frames). 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/ExtendedRmacNetworkLayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef RMACNETWORKLAYER_H_ 17 | #define RMACNETWORKLAYER_H_ 18 | 19 | #include 20 | 21 | #include "CarMobility.h" 22 | #include "ClusterAlgorithm.h" 23 | 24 | /** 25 | * This module implements the clustering mechanism for Robust 26 | * Mobility-Aware Clustering (RMAC). I've made my own extensions. 27 | */ 28 | class ExtendedRmacNetworkLayer : public ClusterAlgorithm, public StatusChangeListener { 29 | 30 | public: 31 | 32 | /** 33 | * @brief Messages used by RMAC. 34 | */ 35 | enum ClusterMessageKinds { 36 | INQ_MESSAGE = LAST_BASE_NETW_MESSAGE_KIND+1, /**< Periodic beacon used to find one-hop neighbours. */ 37 | INQ_RESPONSE_MESSAGE, /**< Inquiry Response. */ 38 | JOIN_MESSAGE, /**< Join a CH. */ 39 | JOIN_RESPONSE_MESSAGE, /**< Response to permit a node to join a cluster. */ 40 | JOIN_DENIAL_MESSAGE, /**< Response to deny a node to join a cluster. */ 41 | JOIN_SUGGEST_MESSAGE, /**< Response to suggest an inquiring node join another CH. */ 42 | POLL_MESSAGE, /**< A poll message. */ 43 | POLL_ACK_MESSAGE, /**< A poll acknowledgement message. */ 44 | SEND_CLUSTER_PRESENCE_MESSAGE, /**< Order edge nodes to send CLUSTER_PRESENCE_MESSAGE. */ 45 | CLUSTER_PRESENCE_MESSAGE, /**< Broadcast a cluster's existence. */ 46 | CLUSTER_UNIFY_REQUEST_MESSAGE, /**< Request to unify disjoint clusters. */ 47 | CLUSTER_UNIFY_RESPONSE_MESSAGE, /**< Response to unification request. */ 48 | LEAVE_MESSAGE, /**< A CM will send its CH this message if it wishes to leave the cluster. */ 49 | DATA, /**< A datagram. */ 50 | LAST_CLUSTER_MESSAGE_KIND 51 | }; 52 | 53 | /** 54 | * @brief Contains the possible states of this node. 55 | */ 56 | enum ClusterState { 57 | UNCLUSTERED = 0, /**< Initial state of all nodes. */ 58 | CLUSTER_MEMBER, /**< This is a member of a cluster. */ 59 | CLUSTER_HEAD, /**< This is the head of a cluster. */ 60 | CLUSTER_HEAD_MEMBER /**< This is the head of a cluster, and a member of another. */ 61 | }; 62 | 63 | /** 64 | * @brief Contains an entry in the neighbour table. 65 | */ 66 | struct Neighbour { 67 | unsigned int mId; /**< Identifier of the neighbour. */ 68 | LAddress::L3Type mNetworkAddress; /**< The IP address of this neighbour. */ 69 | Coord mPosition; /**< Position of the neighbour. */ 70 | Coord mVelocity; /**< Velocity of the neighbour. */ 71 | bool mIsClusterHead; /**< Whether this node is a CH or CHM. */ 72 | unsigned int mClusterHead; /**< ID of the node's CH. */ 73 | unsigned int mConnectionCount; /**< Number of connections this node now has. */ 74 | unsigned int mHopCount; /**< Number of hops this neighbour is from this node. */ 75 | simtime_t mTimeStamp; /**< Last time this entry was updated. */ 76 | unsigned int mProviderId; /**< Identifier of the node that last provided this information. */ 77 | double mDistanceToNode; /**< Distance from this node to this neighbour. */ 78 | double mLinkExpirationTime; /**< Time until this link expires due to mobility. */ 79 | int mMissedPings; /**< Number of times this neighbour has missed a ping. */ 80 | unsigned int mRouteSimilarity; /**< How similar this node's route is to ours. */ 81 | double mLossProbability; /**< The probability that the last message received from this node could have been lost. */ 82 | ExtendedRmacNetworkLayer *mDataOwner; /**< Owner of this data. */ 83 | }; 84 | 85 | /** 86 | * @typedef NeighbourTable 87 | * @brief Contains a table of neighbours. 88 | */ 89 | typedef std::map NeighbourTable; 90 | 91 | /** 92 | * @typedef NeighbourSet 93 | * @brief Contains a set of neighbours. 94 | */ 95 | typedef std::vector NeighbourSet; 96 | 97 | /** 98 | * @typedef NeighbourIterator 99 | * @brief An iterator for the NeighbourSet. 100 | */ 101 | typedef std::map::iterator NeighbourIterator; 102 | 103 | /** 104 | * @name Getters 105 | * @brief Get the data members. 106 | * 107 | * These get the data members. 108 | */ 109 | /*@{*/ 110 | 111 | unsigned int GetConnectionLimits(); /**< Get maximum cluster size. */ 112 | double GetDistanceThreshold(); /**< Get distance threshold. */ 113 | double GetTimeThreshold(); /**< Get time threshold. */ 114 | 115 | /** Get a neighbour with the given id. */ 116 | const Neighbour &GetNeighbour( const int &id ); 117 | 118 | int GetCurrentLevelCount(); 119 | 120 | /*@}*/ 121 | 122 | 123 | int GetStateCount(); 124 | bool IsClusterHead(); 125 | bool IsSubclusterHead(); 126 | bool IsHierarchical(); 127 | int GetClusterState(); 128 | void UpdateMessageString(); 129 | int GetMinimumClusterSize(); 130 | 131 | virtual void ClusterStarted(); 132 | virtual void ClusterMemberAdded( int id ); 133 | virtual void ClusterMemberRemoved( int id ); 134 | virtual void ClusterDied( int deathType ); 135 | 136 | /** 137 | * Default constructor 138 | */ 139 | ExtendedRmacNetworkLayer() { } 140 | 141 | /** @brief Initialization of the module and some variables*/ 142 | virtual void initialize(int); 143 | 144 | /** @brief Cleanup*/ 145 | virtual void finish(); 146 | 147 | 148 | protected: 149 | 150 | /** 151 | * @name Handlers 152 | * @brief OMNeT++ message handler. 153 | * 154 | * These methods handle messages passed to this module. 155 | * 156 | **/ 157 | /*@{*/ 158 | 159 | /** @brief Handle messages from upper layer */ 160 | virtual void handleUpperMsg(cMessage* msg); 161 | 162 | /** @brief Handle messages from lower layer */ 163 | virtual void handleLowerMsg(cMessage* msg); 164 | 165 | /** @brief Handle self messages */ 166 | virtual void handleSelfMsg(cMessage* msg); 167 | 168 | /** @brief decapsulate higher layer message from RmacControlMessage */ 169 | virtual cMessage* decapsMsg(ExtendedRmacControlMessage*); 170 | 171 | /** @brief Encapsulate higher layer packet into a RmacControlMessage */ 172 | virtual NetwPkt* encapsMsg(cPacket*); 173 | 174 | /*@}*/ 175 | 176 | 177 | /** 178 | * @name Cluster Methods 179 | * @brief Methods handling the formation and maintenance of clusters. 180 | * 181 | * These methods are implementations of the RMAC functions as specified 182 | * in the paper "Robust mobility adaptive clustering scheme with support for 183 | * geographic routing for vehicular ad hoc networks" by R.T. Goonewardene et al. 184 | * 185 | **/ 186 | /*@{*/ 187 | 188 | /** 189 | * The set of states the algorithm can be in. 190 | */ 191 | enum ProcessState { 192 | 193 | START = 0, /**< Start of the algorithm. */ 194 | INQUIRY, /**< Inquiry phase. */ 195 | COLLECTING_INQUIRY, /**< We're collecting INQ responses. */ 196 | JOINING, /**< Join request phase. */ 197 | CLUSTERED, /**< Clustered phase. */ 198 | UNIFYING /**< We are unifying with a disjoint cluster. */ 199 | 200 | }; 201 | 202 | ProcessState mProcessState; /**< Current state the process is in. */ 203 | NodeIdList mOneHopNeighbours; /**< One-hop neighbours. */ 204 | 205 | /** 206 | * @brief Process the clustering algorithm. 207 | * @param[in] msg Timeout message, or NULL if none occurred. 208 | * 209 | * This processes the clustering algorithm. 210 | * 211 | * @return Returns true if the function needs to be called again, e.g. if a state change occurred. 212 | */ 213 | bool Process( cMessage *msg = NULL ); 214 | 215 | /** 216 | * @brief Get the one-hop neighbours. 217 | */ 218 | void GetOneHopNeighbours(); 219 | 220 | /** 221 | * @brief Determines whether a nearby cluster is disjoint (true) or connected (false). 222 | */ 223 | bool EvaluateClusterPresence( ExtendedRmacControlMessage *m ); 224 | 225 | /** 226 | * @brief Send an control message 227 | */ 228 | void SendControlMessage( int type, int id = -1, int role = -1 ); 229 | 230 | /** 231 | * @brief Send an INQ broadcast. 232 | */ 233 | void SendInquiry(); 234 | 235 | /** 236 | * @brief Send a INQ_RESP unicast. 237 | * @param[in] id Identifier of the target node. 238 | */ 239 | void SendInquiryResponse( int id ); 240 | 241 | /** 242 | * @brief Send a JOIN request unicast. 243 | * @param[in] id Identifier of the target node. 244 | */ 245 | void SendJoinRequest( int id ); 246 | 247 | /** 248 | * @brief Send a JOIN response unicast. 249 | * @param[in] id Identifier of the target node. 250 | */ 251 | void SendJoinResponse( int id ); 252 | 253 | /** 254 | * @brief Send a JOIN denial unicast. 255 | * @param[in] id Identifier of the target node. 256 | */ 257 | void SendJoinDenial( int id ); 258 | 259 | /** 260 | * @brief Send a POLL unicast to all CMs. 261 | */ 262 | void PollClusterMembers(); 263 | 264 | /** 265 | * @brief Respond to a POLL unicast. 266 | */ 267 | void AcknowledgePoll( int id ); 268 | 269 | /** 270 | * @brief Tell edge nodes to broadcast the cluster presence frame. 271 | */ 272 | void OrderClusterPresenceBroadcast(); 273 | 274 | /** 275 | * @brief Broadcast the cluster presence frame. 276 | */ 277 | void BroadcastClusterPresence(); 278 | 279 | /** 280 | * @brief Send a cluster unification request. 281 | */ 282 | void RequestClusterUnification( int id ); 283 | 284 | /** 285 | * @brief Send a cluster unification response. 286 | */ 287 | void SendUnificationResponse( int id, int role ); 288 | 289 | /** 290 | * @brief Leave the cluster. 291 | */ 292 | void LeaveCluster(); 293 | 294 | 295 | /** 296 | * @brief Calculate the Link Expiration Time. 297 | * @param[in] pos Position of the target node. 298 | * @param[in] vel Velocity of the target node. 299 | * @return The time until the link expires. 300 | */ 301 | 302 | double CalculateLinkExpirationTime( Coord pos, Coord vel ); 303 | 304 | /** 305 | * @brief Calculate the loss probability of a node. 306 | * @param[in] a Parameter A of the channel's Rice distribution. 307 | * @param[in] sigma Parameter Sigma of the channel's Rice distribution. 308 | * @param[in] dSq Square of distance from the neighbour to this node. 309 | * @return The probability that the last received message could have been lost. 310 | */ 311 | 312 | double CalculateLossProbability( double a, double sigma, double dSq ); 313 | 314 | 315 | /** 316 | * @brief Calculate the route similarity of a node. 317 | * @param[in] r Route of the node. 318 | * @return The number of consecutive route links this node has in common with ours. 319 | */ 320 | 321 | int CalculateRouteSimilarity( Route &r ); 322 | 323 | 324 | 325 | /** 326 | * Update neighbour data with the given message. 327 | */ 328 | void UpdateNeighbour( ExtendedRmacControlMessage *m ); 329 | 330 | /*@}*/ 331 | 332 | 333 | //unsigned int mId; /**< The identifier of this node. */ 334 | ClusterState mCurrentState; /**< This is the current state of the node. */ 335 | 336 | NeighbourTable mNeighbours; /**< This node's neighbour table. */ 337 | 338 | NodeIdSet mWaitingPollAcks; /**< IDs of nodes we're awaiting poll responses from. */ 339 | 340 | double mTransmitRangeSq; /**< Transmission range, squared. */ 341 | double mZoneOfInterest; /**< This is double the TX range. Obtained from the PhyLayer module. */ 342 | 343 | bool mInitialised; /**< Set to true if the init function has been called. */ 344 | 345 | // Route mThisRoute; /**< The route of this node. */ 346 | 347 | /** 348 | * @name Messages 349 | * @brief Messages this module sends itself. 350 | * 351 | * These are used for timed events. 352 | * 353 | **/ 354 | /*@{*/ 355 | 356 | cMessage *mFirstTimeProcess; /**< Scheduled when the cluster algorithm starts, to signal the first calling of the Process function. */ 357 | cMessage *mInquiryTimeoutMessage; /**< Scheduled for INQ timeout. */ 358 | cMessage *mInquiryResponseTimeoutMessage; /**< Scheduled for INQ_RESP timeout. */ 359 | cMessage *mJoinTimeoutMessage; /**< Scheduled for JOIN timeout. */ 360 | cMessage *mJoinDenyMessage; /**< Message to signify a JOIN request was denied. */ 361 | cMessage *mPollTriggerMessage; /**< Message to trigger a CH to poll its members. */ 362 | cMessage *mPollTimeoutMessage; /**< Scheduled by CMs and CHMs waiting for poll from their CH. */ 363 | cMessage *mPollPeriodFinishedMessage; /**< Message to signify end of poll period. */ 364 | cMessage *mClusterPresenceBeaconMessage; /**< Message to trigger beaconing of CLUSTER_PRESENCE. */ 365 | cMessage *mClusterUnifyTimeoutMessage; /**< Scheduled for timeout of a unify request. */ 366 | cMessage *mPrepareForSimulationEnd; /**< Signal to log results before simulation ends. */ 367 | 368 | /*@}*/ 369 | 370 | 371 | /** 372 | * @name Parameters 373 | * @brief Module parameters. 374 | * 375 | * These are uses to configure the algorithm. 376 | * 377 | **/ 378 | /*@{*/ 379 | 380 | unsigned int mConnectionLimits; /**< Maximum number of connections this node can have. This is basically an upper limit on the size of the cluster. */ 381 | double mDistanceThreshold; /**< Distance threshold. */ 382 | double mTimeThreshold; /**< Time threshold. */ 383 | double mInquiryPeriod; /**< Period for INQ broadcasts. */ 384 | double mInquiryResponsePeriod; /**< Period during which INQ responses are collated. */ 385 | double mJoinTimeoutPeriod; /**< Period for JOIN timeout. */ 386 | double mPollInterval; /**< Period for CHs polling */ 387 | double mPollTimeout; /**< If a CM doesn't hear a POLL from the CH in this time, it departs the cluster. */ 388 | unsigned int mMissedPingThreshold; /**< Number of pings a node will miss before it is considered gone. */ 389 | unsigned int mRouteSimilarityThreshold; /**< Number of links in a route that will be compared. */ 390 | double mCriticalLossProbability; /**< The highest loss probability before a CM connection is considered dead. */ 391 | 392 | /*@}*/ 393 | 394 | 395 | 396 | /** 397 | * @name Results 398 | * @brief Results to be recorded. 399 | * 400 | * These members record the performance of the algorithm. 401 | * The following performance metrics are recorded: 402 | * 1. Cluster Depth 403 | * This is the maximum number of levels reached by 404 | * a cluster while this node has served as its head. 405 | * Only CHs record this. 406 | * Type: Scalar 407 | * 408 | **/ 409 | /*@{*/ 410 | 411 | simsignal_t mSigClusterDepth; /**< ClusterDepth */ 412 | 413 | /*@}*/ 414 | 415 | /** 416 | * This implements the sorting mechanism for the Node Precidence Algorithm. 417 | */ 418 | struct ExtendedNPA { 419 | bool operator()( const int&, const int& ); 420 | ExtendedRmacNetworkLayer *mClient; 421 | }; 422 | 423 | NodeIdSet mTemporaryClusterRecord; /**< When a node receives a SEND_CLUSTER_PRESENCE_MESSAGE, it stores the cluster member record here. */ 424 | NodeIdList mClusterHierarchy; /**< List of heads of clusters within the hierarchy. This is used to prevent cyclical clusters. */ 425 | std::map mLevelLookup; /**< Lookup table of node IDs and the corresponding depth of their branches in the hierarchy. */ 426 | int mMaximumLevels; /**< Length of the longest branch at this point in the hierarchy. */ 427 | int mCurrentLevels; /**< The largest length this cluster has ever reached. */ 428 | 429 | void UpdateLevelOfMember( int id, NodeIdList& record, bool eraseThis=false ); 430 | 431 | int mReaffiliationCount; 432 | 433 | 434 | /** 435 | * @name StatusChangeListener 436 | * @brief Implementation of the StatusChangeListener class. 437 | **/ 438 | /*@{*/ 439 | 440 | void LaneChanged( int newLane ); 441 | void CrossedIntersection( std::string roadId ); 442 | 443 | /*@}*/ 444 | 445 | }; 446 | 447 | 448 | #define MapHasKey(map,key) ( map.find(key) != map.end() ) 449 | #define ListHasValue(l,v) ( std::find(l.begin(),l.end(),v) != l.end() ) 450 | 451 | #endif /* RMACNETWORKLAYER_H_ */ 452 | -------------------------------------------------------------------------------- /src/ExtendedRmacNetworkLayer.ned: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | package clusterlib; 17 | 18 | import org.mixim.base.modules.BaseNetwLayer; 19 | 20 | // 21 | // This module implements the clustering mechanism for 22 | // Robust Mobility-Aware Clustering (RMAC). I've made some 23 | // of my own modifications. 24 | // 25 | simple ExtendedRmacNetworkLayer extends BaseNetwLayer 26 | { 27 | parameters: 28 | @class(ExtendedRmacNetworkLayer); 29 | 30 | int connectionLimits; // Maximum number of connections this node can have. This is basically an upper limit on the size of the cluster. 31 | double distanceThreshold @unit("m"); // Distance threshold. 32 | double timeThreshold @unit("s"); // Time threshold. 33 | double inquiryPeriod @unit("s"); // Period for INQ broadcasts. 34 | double inquiryResponsePeriod @unit("s"); // Period during which INQ responses are collated. 35 | double joinTimeoutPeriod @unit("s"); // Period for JOIN timeout. 36 | double pollInterval @unit("s"); // Polling interval. 37 | double pollTimeout @unit("s"); // Polling timeout. 38 | int missedPingThreshold; // Maximum number of missed pings before a CM is declared dead. 39 | int routeSimilarityThreshold; // Number of links in a route that will be compared. 40 | double criticalLossProbability; // The highest loss probability before a CM connection is considered dead. 41 | 42 | // signals 43 | @signal[sigOverhead](type="int"); 44 | @signal[sigHelloOverhead](type="int"); 45 | @signal[sigClusterLifetime](type="double"); 46 | @signal[sigClusterSize](type="int"); 47 | @signal[sigHeadChange](type="int"); 48 | @signal[sigDeathType](type="int"); 49 | @signal[sigDeathX](type="double"); 50 | @signal[sigDeathY](type="double"); 51 | @signal[sigClusterDepth](type="int"); 52 | 53 | // statistics 54 | @statistic[ overhead]( source = sigOverhead; record = stats; title = "Overhead per node"; unit = "bytes" ); 55 | @statistic[ helloOverhead]( source = sigHelloOverhead; record = stats; title = "Overhead per node (HELLO messages)"; unit = "bytes" ); 56 | @statistic[clusterLifetime]( source = sigClusterLifetime; record = stats; title = "Cluster Lifetime"; unit = "s" ); 57 | @statistic[ clusterSize]( source = sigClusterSize; record = stats; title = "Cluster Size"; ); 58 | @statistic[ headChange]( source = "count(sigHeadChange)"; record = last; title = "CH changes"; ); 59 | @statistic[ deathType]( source = sigDeathType; record = vector; title = "Cluster Death Types"; ); 60 | @statistic[ deathX]( source = sigDeathX; record = vector; title = "Cluster Death Position X"; ); 61 | @statistic[ deathY]( source = sigDeathY; record = vector; title = "Cluster Death Position Y"; ); 62 | @statistic[ clusterDepth]( source = sigClusterDepth; record = stats; title = "Cluster Depth"; ); 63 | 64 | 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/HighestDegreeCluster.cc: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | 17 | #include "BaseNetwLayer.h" 18 | 19 | #include 20 | 21 | #include "NetwControlInfo.h" 22 | #include "BaseMacLayer.h" 23 | #include "AddressingInterface.h" 24 | #include "SimpleAddress.h" 25 | #include "FindModule.h" 26 | #include "MdmacControlMessage_m.h" 27 | #include "ArpInterface.h" 28 | #include "NetwToMacControlInfo.h" 29 | #include "BaseMobility.h" 30 | #include "BaseConnectionManager.h" 31 | #include "ChannelAccess.h" 32 | 33 | #include "HighestDegreeCluster.h" 34 | 35 | Define_Module(HighestDegreeCluster); 36 | 37 | 38 | /** @brief Compute the CH weight for this node. */ 39 | double HighestDegreeCluster::calculateWeight() { 40 | 41 | return mNeighbours.size(); 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/HighestDegreeCluster.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef __CLUSTERLIB_HIGHESTDEGREECLUSTER_H_ 17 | #define __CLUSTERLIB_HIGHESTDEGREECLUSTER_H_ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include "MdmacControlMessage_m.h" 28 | #include "MdmacNetworkLayer.h" 29 | 30 | /** 31 | * Implements the Highest Degree Clustering mechanism. 32 | * The degree is the number of nodes with which this node has a connection. 33 | */ 34 | class HighestDegreeCluster : public MdmacNetworkLayer { 35 | 36 | protected: 37 | /** @brief Compute the CH weight for this node. */ 38 | double calculateWeight(); 39 | 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/HighestDegreeCluster.ned: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | package clusterlib; 17 | 18 | // 19 | // Implements the Highest Degree Clustering mechanism. 20 | // The degree is the number of nodes with which this node has a connection. 21 | // 22 | simple HighestDegreeCluster extends MdmacNetworkLayer 23 | { 24 | parameters: 25 | @class(HighestDegreeCluster); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/LSUFCluster.cc: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #include "BaseNetwLayer.h" 17 | 18 | #include 19 | 20 | #include "NetwControlInfo.h" 21 | #include "BaseMacLayer.h" 22 | #include "AddressingInterface.h" 23 | #include "SimpleAddress.h" 24 | #include "FindModule.h" 25 | #include "MdmacControlMessage_m.h" 26 | #include "ArpInterface.h" 27 | #include "NetwToMacControlInfo.h" 28 | #include "BaseMobility.h" 29 | #include "BaseConnectionManager.h" 30 | #include "ChannelAccess.h" 31 | 32 | #include "LSUFCluster.h" 33 | 34 | 35 | Define_Module(LSUFCluster); 36 | 37 | LSUFData *LSUFCluster::mLaneWeightData = NULL; 38 | 39 | 40 | /** @brief Initialization of the module and some variables*/ 41 | void LSUFCluster::initialize( int stage ) { 42 | 43 | if ( stage == 0 ) { 44 | 45 | if ( LSUFCluster::mLaneWeightData == NULL ) { 46 | try { 47 | LSUFCluster::mLaneWeightData = new LSUFData( par("laneWeightFile").stringValue() ); 48 | } catch( const char *e ) { 49 | opp_error( e ); 50 | } 51 | } 52 | 53 | LSUFCluster::mLaneWeightData->addRef(); 54 | 55 | } 56 | 57 | MdmacNetworkLayer::initialize( stage ); 58 | 59 | } 60 | 61 | /** @brief Cleanup*/ 62 | void LSUFCluster::finish() { 63 | 64 | if ( LSUFCluster::mLaneWeightData != NULL ) { 65 | 66 | LSUFCluster::mLaneWeightData->release(); 67 | if ( LSUFCluster::mLaneWeightData->getReferenceCount() == 0 ) { 68 | delete LSUFCluster::mLaneWeightData; 69 | LSUFCluster::mLaneWeightData = NULL; 70 | } 71 | 72 | } 73 | 74 | MdmacNetworkLayer::finish(); 75 | 76 | } 77 | 78 | 79 | /** @brief Compute the CH weight for this node. */ 80 | double LSUFCluster::calculateWeight() { 81 | 82 | /* 83 | * Overview of LSUF: 84 | * This is based on Utility-Function clustering. 85 | * The metric is a weight computed from statistics of 86 | * node placement around the node computing its own weight, 87 | * as well as the lane it is in. 88 | */ 89 | 90 | // If the module hasn't been initialised yet, return zero. 91 | if ( !mInitialised ) 92 | return 0; 93 | 94 | // Fetch the weight of this lane, and it's flow ID 95 | float laneWeight; 96 | unsigned char flow; 97 | if ( !LSUFCluster::mLaneWeightData->getLaneWeight( mRoadID+"_"+mLaneID, &laneWeight, &flow ) ) 98 | opp_error( "Tried to get weight for an unknown lane '%s' for current node #%d", (mRoadID+"_"+mLaneID).c_str(), mId ); 99 | 100 | /* 101 | * Now that we have the weight, we have to iterate through the neighbour table. 102 | * We calculate the Network Connectivity Level, the Average Distance Level, 103 | * and Average Velocity Level. 104 | */ 105 | int alpha = mNeighbours.size(); 106 | int beta = 0; 107 | float delta = 0, chi = 0, sigma = 0, rho = 0; 108 | for ( NeighbourIterator it = mNeighbours.begin(); it != mNeighbours.end(); it++ ) { 109 | 110 | // This check does not appear to be part of the original algorithm. 111 | if( it->second.mRoadID != mRoadID ) 112 | continue; // We don't want to cluster with cars that are not on the same road as us. 113 | 114 | // Calculate distance and difference in velocity 115 | float dist, dv; 116 | dist = mMobility->getCurrentPosition().distance( it->second.mPosition ); 117 | dv = mMobility->getCurrentSpeed().distance( it->second.mVelocity ); 118 | 119 | delta += dist; 120 | sigma += dv; 121 | 122 | // Get the flow ID of this neighbour. 123 | unsigned char currFlow; 124 | if ( !LSUFCluster::mLaneWeightData->getLaneWeight( it->second.mRoadID+"_"+it->second.mLaneID, NULL, &currFlow ) ) 125 | opp_error( "Tried to get weight for an unknown lane '%s' for current node #%d", (it->second.mRoadID+"_"+it->second.mLaneID).c_str(), it->first ); 126 | 127 | if ( currFlow == flow ) { 128 | // This car is part of the same flow. 129 | chi += dist; 130 | rho += dv; 131 | beta++; 132 | } 133 | 134 | } 135 | 136 | delta /= alpha; 137 | sigma /= alpha; 138 | chi /= beta; 139 | rho /= beta; 140 | 141 | float NCL, ADL, AVL; 142 | 143 | NCL = beta + alpha * laneWeight; 144 | ADL = delta + chi * laneWeight; 145 | AVL = sigma + rho * laneWeight; 146 | 147 | return NCL + ADL + AVL; 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/LSUFCluster.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef __CLUSTERLIB_LSUFCLUSTER_H_ 17 | #define __CLUSTERLIB_LSUFCLUSTER_H_ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include "MdmacControlMessage_m.h" 28 | #include "MdmacNetworkLayer.h" 29 | 30 | #include "LSUFData.h" 31 | 32 | /** 33 | * Implements the Lane-Sense Utility Function (LSUF) Clustering metric. 34 | */ 35 | class LSUFCluster : public MdmacNetworkLayer 36 | { 37 | public: 38 | /** @brief Initialization of the module and some variables*/ 39 | void initialize(int); 40 | 41 | /** @brief Cleanup*/ 42 | void finish(); 43 | 44 | protected: 45 | 46 | static LSUFData *mLaneWeightData; 47 | 48 | /** @brief Compute the CH weight for this node. */ 49 | double calculateWeight(); 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/LSUFCluster.ned: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | package clusterlib; 17 | 18 | // 19 | // Implements the Lane-Sense Utility Function (LSUF) Clustering metric. 20 | // 21 | simple LSUFCluster extends MdmacNetworkLayer 22 | { 23 | parameters: 24 | @class(LSUFCluster); 25 | string laneWeightFile; 26 | } 27 | -------------------------------------------------------------------------------- /src/LSUFData.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * LSUFData.cpp 3 | * 4 | * Created on: Jun 18, 2013 5 | * Author: craig 6 | */ 7 | 8 | #include 9 | #include "LSUFData.h" 10 | 11 | 12 | 13 | 14 | /** Default constructor */ 15 | LSUFData::LSUFData( const char *filename ) { 16 | 17 | std::ifstream ins; 18 | ins.open( filename ); 19 | 20 | if ( ins.fail() ) 21 | throw "Could not load LSUF datafile"; 22 | 23 | int count; 24 | ins >> std::dec >> count; 25 | 26 | for ( int i = 0; i < count; i++ ) { 27 | 28 | std::string laneName; 29 | float weight; 30 | unsigned char flow; 31 | 32 | ins >> laneName >> weight >> flow; 33 | 34 | mLaneWeights[laneName].mWeight = weight; 35 | mLaneWeights[laneName].mFlowID = flow; 36 | 37 | } 38 | 39 | ins.close(); 40 | 41 | } 42 | 43 | 44 | /** Default destructor */ 45 | LSUFData::~LSUFData() { 46 | 47 | mLaneWeights.clear(); 48 | 49 | } 50 | 51 | 52 | 53 | /** Get the number of references to this data container. */ 54 | unsigned int LSUFData::getReferenceCount() { 55 | 56 | return mReferenceCount; 57 | 58 | } 59 | 60 | 61 | /** Increment the reference counter. */ 62 | void LSUFData::addRef() { 63 | 64 | mReferenceCount++; 65 | 66 | } 67 | 68 | 69 | /** Decrement the reference counter. */ 70 | void LSUFData::release() { 71 | 72 | mReferenceCount--; 73 | 74 | } 75 | 76 | 77 | /** Get the weight and flow ID of the given lane. */ 78 | bool LSUFData::getLaneWeight( std::string strLane, float *weight, unsigned char *flow ) { 79 | 80 | if ( mLaneWeights.find( strLane ) == mLaneWeights.end() ) { 81 | *flow = 0; 82 | *weight = 1; 83 | return true; 84 | } 85 | 86 | if ( weight ) 87 | *weight = mLaneWeights[strLane].mWeight; 88 | 89 | if ( flow ) 90 | *flow = mLaneWeights[strLane].mFlowID; 91 | 92 | return true; 93 | 94 | } 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/LSUFData.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LSUFData.h 3 | * 4 | * Created on: Jun 18, 2013 5 | * Author: craig 6 | */ 7 | 8 | #ifndef LSUFDATA_H_ 9 | #define LSUFDATA_H_ 10 | 11 | #include 12 | 13 | class LSUFData { 14 | 15 | protected: 16 | 17 | /** 18 | * @brief Contains the weight of the lane. 19 | */ 20 | typedef struct LaneWeight { 21 | float mWeight; /**< The weight of this lane. */ 22 | unsigned char mFlowID; /**< The ID of the flow to which this lane belongs. */ 23 | } LaneWeight; 24 | 25 | typedef std::map LaneWeightData; 26 | 27 | LaneWeightData mLaneWeights; /**< The lane weights. */ 28 | unsigned int mReferenceCount; /**< The number of modules currently referencing this data container. */ 29 | 30 | public: 31 | /** Default constructor */ 32 | LSUFData( const char *filename ); 33 | 34 | /** Default destructor */ 35 | virtual ~LSUFData(); 36 | 37 | /** Get the number of references to this data container. */ 38 | unsigned int getReferenceCount(); 39 | 40 | /** Increment the reference counter. */ 41 | void addRef(); 42 | 43 | /** Decrement the reference counter. */ 44 | void release(); 45 | 46 | /** Get the weight and flow ID of the given lane. */ 47 | bool getLaneWeight( std::string strLane, float *weight, unsigned char *flow ); 48 | 49 | }; 50 | 51 | #endif /* LSUFDATA_H_ */ 52 | -------------------------------------------------------------------------------- /src/LowestIdCluster.cc: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | 17 | #include "BaseNetwLayer.h" 18 | 19 | #include 20 | 21 | #include "NetwControlInfo.h" 22 | #include "BaseMacLayer.h" 23 | #include "AddressingInterface.h" 24 | #include "SimpleAddress.h" 25 | #include "FindModule.h" 26 | #include "MdmacControlMessage_m.h" 27 | #include "ArpInterface.h" 28 | #include "NetwToMacControlInfo.h" 29 | #include "BaseMobility.h" 30 | #include "BaseConnectionManager.h" 31 | #include "ChannelAccess.h" 32 | 33 | #include "LowestIdCluster.h" 34 | 35 | Define_Module(LowestIdCluster); 36 | 37 | 38 | /** @brief Compute the CH weight for this node. */ 39 | double LowestIdCluster::calculateWeight() { 40 | 41 | return -mId; 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/LowestIdCluster.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef __CLUSTERLIB_LOWESTIDCLUSTER_H_ 17 | #define __CLUSTERLIB_LOWESTIDCLUSTER_H_ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include "MdmacControlMessage_m.h" 28 | #include "MdmacNetworkLayer.h" 29 | 30 | /** 31 | * Implements the Lowest ID Clustering mechanism. 32 | */ 33 | class LowestIdCluster : public MdmacNetworkLayer 34 | { 35 | protected: 36 | /** @brief Compute the CH weight for this node. */ 37 | double calculateWeight(); 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/LowestIdCluster.ned: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | package clusterlib; 17 | 18 | 19 | // 20 | // Implements the Lowest ID Clustering mechanism. 21 | // 22 | simple LowestIdCluster extends MdmacNetworkLayer 23 | { 24 | parameters: 25 | @class(LowestIdCluster); 26 | } 27 | -------------------------------------------------------------------------------- /src/MarcumQ.cc: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU Lesser General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU Lesser General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU Lesser General Public License 14 | // along with this program. If not, see http://www.gnu.org/licenses/. 15 | // 16 | 17 | 18 | // Need this for Marcum Q function 19 | #include 20 | #include "MarcumQ.h" 21 | 22 | 23 | 24 | // Helper function to compute factorials. 25 | inline int factorial(int x) { 26 | return (x <= 1 ? 1 : x * factorial(x - 1)); 27 | } 28 | 29 | 30 | /** 31 | * This computes the Marcum Q function 32 | */ 33 | double MarcumQ( double a, double b, int M ) { 34 | 35 | 36 | // Special cases. 37 | if ( b == 0 ) 38 | return 1; 39 | 40 | if ( a == 0 ) { 41 | double Q=0; 42 | for ( int k = 0; k <= M-1; k++ ) 43 | Q += pow(b,2*k)/(pow(2.0,k) * factorial(k)); 44 | return Q * exp(-pow(b,2)/2); 45 | } 46 | 47 | // The basic iteration. If a std::numeric_limits::epsilon() ); 85 | 86 | return constant + qSign * exp( -pow( a-b, 2 ) / 2 ) * S; 87 | 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/MarcumQ.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef __MARCUM_Q 17 | #define __MARCUM_Q 18 | 19 | 20 | 21 | /** 22 | * This computes the Marcum Q function 23 | */ 24 | double MarcumQ( double a, double b, int M = 1 ); 25 | 26 | 27 | 28 | #endif /* #ifndef __MARCUM_Q */ 29 | -------------------------------------------------------------------------------- /src/MdmacControlMessage.msg: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | cplusplus {{ 17 | #include "NetwPkt_m.h" 18 | 19 | typedef std::list StringList; 20 | }} 21 | packet NetwPkt; 22 | 23 | class noncobject StringList; 24 | 25 | // 26 | // Describes the M-DMAC cluster control message. 27 | // Extends the NetwPkt, so this can be used to encapsulate 28 | // application layer packets as well. 29 | // 30 | packet MdmacControlMessage extends NetwPkt { 31 | 32 | int nodeId; 33 | double weight; 34 | bool isClusterHead; 35 | double xPosition; 36 | double yPosition; 37 | double xVelocity; 38 | double yVelocity; 39 | string roadId; 40 | string laneId; 41 | double xDestination; 42 | double yDestination; 43 | StringList route; 44 | int targetNodeId; // ID of the CH I wish to join (used for JOIN_MESSAGE type) 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/MdmacNetworkLayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef __CLUSTERLIB_CLUSTERNETWORKLAYER_H_ 17 | #define __CLUSTERLIB_CLUSTERNETWORKLAYER_H_ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "ClusterAlgorithm.h" 29 | 30 | #define BEAT_LENGTH 0.25 // measured in second. 31 | 32 | /** 33 | * This module implements the clustering mechanism for 34 | * Modified Distributed Mobility-Aware Clustering (M-DMAC). 35 | * There is a pure virtual function that must be implemented by 36 | * inheriting cluster modules, which provides the weighting function 37 | * for the particular cluster algorithm being tested. 38 | */ 39 | class MdmacNetworkLayer : public ClusterAlgorithm 40 | { 41 | 42 | public: 43 | 44 | /** 45 | * @brief Messages used by the clustering mechanism. 46 | */ 47 | enum ClusterMessageKinds { 48 | HELLO_MESSAGE = LAST_BASE_NETW_MESSAGE_KIND+1, /**< Periodic beacon used to update node weights. */ 49 | CH_MESSAGE, /**< Announcement that a node has become a Cluster Head (CH). */ 50 | JOIN_MESSAGE, /**< Announcement of a node's intention to join a CH. */ 51 | DATA, /**< A datagram. */ 52 | LAST_CLUSTER_MESSAGE_KIND 53 | }; 54 | 55 | 56 | typedef std::list RouteLinkList; 57 | 58 | struct Neighbour { 59 | double mWeight; /**< Weight of this node. */ 60 | Coord mPosition; /**< Position of the Neighbour. */ 61 | Coord mVelocity; /**< Velocity of the Neighbour. */ 62 | std::string mRoadID; /**< The ID of the road this car is on. */ 63 | std::string mLaneID; /**< The ID of the lane this car is on. */ 64 | Coord mDestination; /**< The node's destination. */ 65 | RouteLinkList mRouteLinks; /**< The next N links in this neighbour's route. */ 66 | bool mIsClusterHead; /**< Is this node a CH? */ 67 | unsigned int mFreshness; /**< How long this node will stay in range of this neighbour. Measured in beats. */ 68 | }; 69 | 70 | protected: 71 | 72 | 73 | typedef std::map NeighbourSet; 74 | typedef std::map::iterator NeighbourIterator; 75 | 76 | //unsigned int mID; /**< Node's unique ID. */ 77 | double mWeight; /**< Weight of this node. */ 78 | 79 | std::string mRoadID; /**< The ID of the road this car is on. */ 80 | std::string mLaneID; /**< The ID of the lane this car is on. */ 81 | 82 | bool mIncludeDestination; /**< Include the destination in the HELLO messages. */ 83 | 84 | bool mIsClusterHead; /**< Is this node a CH? */ 85 | NeighbourSet mNeighbours; /**< The set of neighbours near this node. */ 86 | 87 | double mTransmitRangeSq; /**< Required for the freshness calculation. Obtained from the PhyLayer module. */ 88 | 89 | bool mInitialised; /**< Set to true if the init function has been called. */ 90 | 91 | /** 92 | * @name Messages 93 | * @brief Messages this module sends itself. 94 | * 95 | * These are used for timed events. 96 | * 97 | **/ 98 | /*@{*/ 99 | 100 | cMessage *mFirstInitMessage; /**< Run the cluster init function for the first time. */ 101 | cMessage *mSendHelloMessage; /**< Send a HELLO message. */ 102 | cMessage *mBeatMessage; /**< Process the neighbour table for out-of-date node entries. */ 103 | 104 | /*@}*/ 105 | 106 | 107 | /** 108 | * @name Parameters 109 | * @brief Configurations for the module. 110 | * 111 | * These variables are set in the simulation configuration. 112 | * 113 | **/ 114 | /*@{*/ 115 | 116 | unsigned int mInitialFreshness; /**< The initial node freshness (measured in beats). */ 117 | unsigned int mFreshnessThreshold; /**< The minimum freshness for which a node is eligible to be a CH. */ 118 | double mAngleThreshold; /**< The maximum angle between the directions of this node and another node for it to be considered for CH. */ 119 | unsigned int mHopCount; /**< The number of hops for cluster control messages. */ 120 | double mBeaconInterval; /**< The interval between each HELLO message. */ 121 | 122 | /*@}*/ 123 | 124 | 125 | 126 | 127 | public: 128 | //Module_Class_Members(BaseNetwLayer,BaseLayer,0); 129 | MdmacNetworkLayer() : ClusterAlgorithm() {} 130 | 131 | 132 | /** @brief Initialization of the module and some variables*/ 133 | virtual void initialize(int); 134 | 135 | /** @brief Cleanup*/ 136 | virtual void finish(); 137 | 138 | 139 | int GetStateCount(); 140 | int GetClusterState(); 141 | bool IsClusterHead(); 142 | bool IsSubclusterHead(); 143 | bool IsHierarchical(); 144 | void UpdateMessageString(); 145 | int GetMinimumClusterSize(); 146 | 147 | void ClusterStarted(); 148 | void ClusterDied( int deathType ); 149 | 150 | protected: 151 | 152 | /** @brief Handle messages from upper layer */ 153 | virtual void handleUpperMsg(cMessage* msg); 154 | 155 | /** @brief Handle messages from lower layer */ 156 | virtual void handleLowerMsg(cMessage* msg); 157 | 158 | /** @brief Handle self messages */ 159 | virtual void handleSelfMsg(cMessage* msg); 160 | 161 | /** @brief decapsulate higher layer message from ClusterControlMessage */ 162 | virtual cMessage* decapsMsg(MdmacControlMessage*); 163 | 164 | /** @brief Encapsulate higher layer packet into a ClusterControlMessage */ 165 | virtual NetwPkt* encapsMsg(cPacket*); 166 | 167 | /** @brief Compute the CH weight for this node. */ 168 | virtual double calculateWeight(); 169 | 170 | /** Add the destination data to a packet. */ 171 | virtual int AddDestinationData( MdmacControlMessage *pkt ); 172 | 173 | /** Store the destination data from a packet. */ 174 | virtual void StoreDestinationData( MdmacControlMessage *pkt ); 175 | 176 | /** 177 | * @name Cluster Methods 178 | * @brief Methods handling the formation and maintenance of clusters. 179 | * 180 | * These methods are implementations of the M-DMAC functions as specified 181 | * in the paper "Modified DMAC Clustering Algorithm for VANETs" by G. Wolny 182 | * 183 | **/ 184 | /*@{*/ 185 | 186 | /** @brief Initiate clustering. */ 187 | void init(); 188 | 189 | /** @brief Process the neighbour table in one beat. Also, update the node's weight. */ 190 | void processBeat(); 191 | 192 | /** @brief Select a CH from the neighbour table. */ 193 | int chooseClusterHead(); 194 | 195 | /** @brief Handle a link failure. Link failure is detected when a CMs freshness reaches 0. */ 196 | void linkFailure( unsigned int ); 197 | 198 | /** @brief Calculate the freshness of the given neighbour. */ 199 | void calculateFreshness( unsigned int ); 200 | 201 | /** @brief Determine whether the given node is a suitable CH. */ 202 | bool testClusterHeadChange( unsigned int ); 203 | 204 | /** @brief Handle a HELLO message. */ 205 | void receiveHelloMessage( MdmacControlMessage* ); 206 | 207 | /** @brief Handle a CH message. */ 208 | void receiveChMessage( MdmacControlMessage* ); 209 | 210 | /** @brief Handle a JOIN message. */ 211 | void receiveJoinMessage( MdmacControlMessage* ); 212 | 213 | /** @brief Update a neighbour's data. */ 214 | void updateNeighbour( MdmacControlMessage* ); 215 | 216 | /** @brief Sends a given cluster message. */ 217 | void sendClusterMessage( int, int = -1, int = -1 ); 218 | 219 | /*@}*/ 220 | 221 | }; 222 | 223 | #endif 224 | -------------------------------------------------------------------------------- /src/MdmacNetworkLayer.ned: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | package clusterlib; 17 | 18 | import org.mixim.base.modules.BaseNetwLayer; 19 | 20 | // 21 | // This module implements the clustering mechanism for 22 | // Modified Distributed Mobility-Aware Clustering (M-DMAC). 23 | // There is a pure virtual function that must be implemented by 24 | // inheriting cluster modules, which provides the weighting function 25 | // for the particular cluster algorithm being tested. 26 | // 27 | simple MdmacNetworkLayer extends BaseNetwLayer 28 | { 29 | parameters: 30 | @class(MdmacNetworkLayer); 31 | 32 | int initialFreshness = default(10); 33 | int freshnessThreshold = default(4); 34 | double angleThreshold = default(0.25); // multiple of PI 35 | int hopCount = default(1); 36 | double beaconInterval @unit(s) = default(20s); 37 | 38 | // signals 39 | @signal[sigOverhead](type="int"); 40 | @signal[sigHelloOverhead](type="int"); 41 | @signal[sigClusterLifetime](type="double"); 42 | @signal[sigClusterSize](type="int"); 43 | @signal[sigHeadChange](type="int"); 44 | @signal[sigDeathType](type="int"); 45 | @signal[sigDeathX](type="double"); 46 | @signal[sigDeathY](type="double"); 47 | 48 | // statistics 49 | @statistic[ overhead]( source = sigOverhead; record = stats; title = "Overhead per node"; unit = "bytes" ); 50 | @statistic[ helloOverhead]( source = sigHelloOverhead; record = stats; title = "Overhead per node (HELLO messages)"; unit = "bytes" ); 51 | @statistic[clusterLifetime]( source = sigClusterLifetime; record = stats; title = "Cluster Lifetime"; unit = "s" ); 52 | @statistic[ clusterSize]( source = sigClusterSize; record = stats; title = "Cluster Size"; ); 53 | @statistic[ headChange]( source = "count(sigHeadChange)"; record = last; title = "CH changes"; ); 54 | @statistic[ deathType]( source = sigDeathType; record = vector; title = "Cluster Death Types"; ); 55 | @statistic[ deathX]( source = sigDeathX; record = vector; title = "Cluster Death Position X"; ); 56 | @statistic[ deathY]( source = sigDeathY; record = vector; title = "Cluster Death Position Y"; ); 57 | 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/RMACData.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef RMACDATA_H_ 17 | #define RMACDATA_H_ 18 | 19 | class RmacNetworkLayer; 20 | 21 | /** 22 | * @brief Contains an entry in the RMAC neighbour table. 23 | */ 24 | struct NeighbourEntry { 25 | unsigned int mId; /**< Identifier of the neighbour. */ 26 | LAddress::L3Type mNetworkAddress; /**< The IP address of this neighbour. */ 27 | double mPositionX; /**< Position of the neighbour (X). */ 28 | double mPositionY; /**< Position of the neighbour (Y). */ 29 | double mVelocityX; /**< Velocity of the neighbour (X). */ 30 | double mVelocityY; /**< Velocity of the neighbour (Y). */ 31 | bool mIsClusterHead; /**< Whether this node is a CH or CHM. */ 32 | unsigned int mClusterHead; /**< ID of the node's CH. */ 33 | unsigned int mConnectionCount; /**< Number of connections this node now has. */ 34 | unsigned int mHopCount; /**< Number of hops this neighbour is from this node. */ 35 | unsigned int mMissedPings; /**< Number of times this node has missed a ping. */ 36 | unsigned int mRouteSimilarity; /**< How similar is this neighbour's route to ours? */ 37 | simtime_t mTimeStamp; /**< Timestamp of this data. */ 38 | }; 39 | 40 | typedef std::vector NeighbourEntrySet; 41 | typedef NeighbourEntrySet::iterator NeighbourEntrySetIterator; 42 | 43 | typedef std::vector NeighbourIdSet; 44 | typedef NeighbourIdSet::iterator NeighbourIdSetIterator; 45 | 46 | typedef std::list Route; 47 | 48 | #endif /* #define RMACDATA_H_ */ 49 | -------------------------------------------------------------------------------- /src/RmacControlMessage.msg: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | cplusplus {{ 17 | #include "NetwPkt_m.h" 18 | #include "RMACData.h" 19 | }} 20 | packet NetwPkt; 21 | 22 | 23 | class noncobject NeighbourEntrySet; 24 | class noncobject NeighbourIdSet; 25 | 26 | // 27 | // Describes the RMAC cluster control message. 28 | // Extends the NetwPkt, so this can be used to encapsulate 29 | // application layer packets as well. 30 | // 31 | packet RmacControlMessage extends NetwPkt { 32 | 33 | int nodeId; // Identifier of the neighbour. 34 | double xPosition; // X-Position of the neighbour. 35 | double yPosition; // Y-Position of the neighbour. 36 | double xVelocity; // X-Velocity of the neighbour. 37 | double yVelocity; // Y-Velocity of the neighbour. 38 | bool isClusterHead; // Is this node a CH or CHM? 39 | int clusterHead; // ID of this node's CH. 40 | unsigned int connectionCount; // Number of connections this node has. 41 | NeighbourEntrySet neighbourTable; // Neighbour table of this node. 42 | NeighbourIdSet neighbourIdTable; // Set of IDs in neighbour table (used for CLUS_PRES frames). 43 | NeighbourIdSet clusterHierarchy; // Sequence of cluster heads (used to prevent cyclical clusters). 44 | int proposedRole; // Proposed role of this node (used for CLUS_UNIFY_REQ frames). 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/RmacNetworkLayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef RMACNETWORKLAYER_H_ 17 | #define RMACNETWORKLAYER_H_ 18 | 19 | #include 20 | 21 | #include "ClusterAlgorithm.h" 22 | 23 | /** 24 | * This module implements the clustering mechanism for Robust 25 | * Mobility-Aware Clustering (RMAC). 26 | */ 27 | class RmacNetworkLayer : public ClusterAlgorithm { 28 | 29 | public: 30 | 31 | /** 32 | * @brief Messages used by RMAC. 33 | */ 34 | enum ClusterMessageKinds { 35 | INQ_MESSAGE = LAST_BASE_NETW_MESSAGE_KIND+1, /**< Periodic beacon used to find one-hop neighbours. */ 36 | INQ_RESPONSE_MESSAGE, /**< Inquiry Response. */ 37 | JOIN_MESSAGE, /**< Join a CH. */ 38 | JOIN_RESPONSE_MESSAGE, /**< Response to permit a node to join a cluster. */ 39 | JOIN_DENIAL_MESSAGE, /**< Response to deny a node to join a cluster. */ 40 | POLL_MESSAGE, /**< A poll message. */ 41 | POLL_ACK_MESSAGE, /**< A poll acknowledgement message. */ 42 | SEND_CLUSTER_PRESENCE_MESSAGE, /**< Order edge nodes to send CLUSTER_PRESENCE_MESSAGE. */ 43 | CLUSTER_PRESENCE_MESSAGE, /**< Broadcast a cluster's existence. */ 44 | CLUSTER_UNIFY_REQUEST_MESSAGE, /**< Request to unify disjoint clusters. */ 45 | CLUSTER_UNIFY_RESPONSE_MESSAGE, /**< Response to unification request. */ 46 | LEAVE_MESSAGE, /**< A CM will send its CH this message if it wishes to leave the cluster. */ 47 | DATA, /**< A datagram. */ 48 | LAST_CLUSTER_MESSAGE_KIND 49 | }; 50 | 51 | /** 52 | * @brief Contains the possible states of this node. 53 | */ 54 | enum ClusterState { 55 | UNCLUSTERED = 0, /**< Initial state of all nodes. */ 56 | CLUSTER_MEMBER, /**< This is a member of a cluster. */ 57 | CLUSTER_HEAD, /**< This is the head of a cluster. */ 58 | CLUSTER_HEAD_MEMBER /**< This is the head of a cluster, and a member of another. */ 59 | }; 60 | 61 | /** 62 | * @brief Contains an entry in the neighbour table. 63 | */ 64 | struct Neighbour { 65 | unsigned int mId; /**< Identifier of the neighbour. */ 66 | LAddress::L3Type mNetworkAddress; /**< The IP address of this neighbour. */ 67 | Coord mPosition; /**< Position of the neighbour. */ 68 | Coord mVelocity; /**< Velocity of the neighbour. */ 69 | bool mIsClusterHead; /**< Whether this node is a CH or CHM. */ 70 | unsigned int mClusterHead; /**< ID of the node's CH. */ 71 | unsigned int mConnectionCount; /**< Number of connections this node now has. */ 72 | unsigned int mHopCount; /**< Number of hops this neighbour is from this node. */ 73 | simtime_t mTimeStamp; /**< Last time this entry was updated. */ 74 | unsigned int mProviderId; /**< Identifier of the node that last provided this information. */ 75 | double mDistanceToNode; /**< Distance from this node to this neighbour. */ 76 | double mLinkExpirationTime; /**< Time until this link expires due to mobility. */ 77 | int mMissedPings; /**< Number of times this neighbour has missed a ping. */ 78 | RmacNetworkLayer *mDataOwner; /**< Owner of this data. */ 79 | }; 80 | 81 | /** 82 | * @typedef NeighbourTable 83 | * @brief Contains a table of neighbours. 84 | */ 85 | typedef std::map NeighbourTable; 86 | 87 | /** 88 | * @typedef NeighbourSet 89 | * @brief Contains a set of neighbours. 90 | */ 91 | typedef std::vector NeighbourSet; 92 | 93 | /** 94 | * @typedef NeighbourIterator 95 | * @brief An iterator for the NeighbourSet. 96 | */ 97 | typedef std::map::iterator NeighbourIterator; 98 | 99 | /** 100 | * @name Getters 101 | * @brief Get the data members. 102 | * 103 | * These get the data members. 104 | */ 105 | /*@{*/ 106 | 107 | unsigned int GetConnectionLimits(); /**< Get maximum cluster size. */ 108 | double GetDistanceThreshold(); /**< Get distance threshold. */ 109 | double GetTimeThreshold(); /**< Get time threshold. */ 110 | 111 | /** Get a neighbour with the given id. */ 112 | const Neighbour &GetNeighbour( const int &id ); 113 | 114 | int GetCurrentLevelCount(); 115 | 116 | /*@}*/ 117 | 118 | 119 | int GetStateCount(); 120 | bool IsClusterHead(); 121 | bool IsSubclusterHead(); 122 | bool IsHierarchical(); 123 | int GetClusterState(); 124 | void UpdateMessageString(); 125 | int GetMinimumClusterSize(); 126 | 127 | virtual void ClusterStarted(); 128 | virtual void ClusterMemberAdded( int id ); 129 | virtual void ClusterMemberRemoved( int id ); 130 | virtual void ClusterDied( int deathType ); 131 | 132 | /** 133 | * Default constructor 134 | */ 135 | RmacNetworkLayer() { } 136 | 137 | /** @brief Initialization of the module and some variables*/ 138 | virtual void initialize(int); 139 | 140 | /** @brief Cleanup*/ 141 | virtual void finish(); 142 | 143 | 144 | protected: 145 | 146 | /** 147 | * @name Handlers 148 | * @brief OMNeT++ message handler. 149 | * 150 | * These methods handle messages passed to this module. 151 | * 152 | **/ 153 | /*@{*/ 154 | 155 | /** @brief Handle messages from upper layer */ 156 | virtual void handleUpperMsg(cMessage* msg); 157 | 158 | /** @brief Handle messages from lower layer */ 159 | virtual void handleLowerMsg(cMessage* msg); 160 | 161 | /** @brief Handle self messages */ 162 | virtual void handleSelfMsg(cMessage* msg); 163 | 164 | /** @brief decapsulate higher layer message from RmacControlMessage */ 165 | virtual cMessage* decapsMsg(RmacControlMessage*); 166 | 167 | /** @brief Encapsulate higher layer packet into a RmacControlMessage */ 168 | virtual NetwPkt* encapsMsg(cPacket*); 169 | 170 | /*@}*/ 171 | 172 | 173 | /** 174 | * @name Cluster Methods 175 | * @brief Methods handling the formation and maintenance of clusters. 176 | * 177 | * These methods are implementations of the RMAC functions as specified 178 | * in the paper "Robust mobility adaptive clustering scheme with support for 179 | * geographic routing for vehicular ad hoc networks" by R.T. Goonewardene et al. 180 | * 181 | **/ 182 | /*@{*/ 183 | 184 | /** 185 | * The set of states the algorithm can be in. 186 | */ 187 | enum ProcessState { 188 | 189 | START = 0, /**< Start of the algorithm. */ 190 | INQUIRY, /**< Inquiry phase. */ 191 | COLLECTING_INQUIRY, /**< We're collecting INQ responses. */ 192 | JOINING, /**< Join request phase. */ 193 | CLUSTERED, /**< Clustered phase. */ 194 | UNIFYING /**< We are unifying with a disjoint cluster. */ 195 | 196 | }; 197 | 198 | ProcessState mProcessState; /**< Current state the process is in. */ 199 | NodeIdList mOneHopNeighbours; /**< One-hop neighbours. */ 200 | 201 | /** 202 | * @brief Process the clustering algorithm. 203 | * @param[in] msg Timeout message, or NULL if none occurred. 204 | * 205 | * This processes the clustering algorithm. 206 | * 207 | * @return Returns true if the function needs to be called again, e.g. if a state change occurred. 208 | */ 209 | bool Process( cMessage *msg = NULL ); 210 | 211 | /** 212 | * @brief Get the one-hop neighbours. 213 | */ 214 | void GetOneHopNeighbours(); 215 | 216 | /** 217 | * @brief Determines whether a nearby cluster is disjoint (true) or connected (false). 218 | */ 219 | bool EvaluateClusterPresence( RmacControlMessage *m ); 220 | 221 | /** 222 | * @brief Send an control message 223 | */ 224 | void SendControlMessage( int type, int id = -1, int role = -1 ); 225 | 226 | /** 227 | * @brief Send an INQ broadcast. 228 | */ 229 | void SendInquiry(); 230 | 231 | /** 232 | * @brief Send a INQ_RESP unicast. 233 | * @param[in] id Identifier of the target node. 234 | */ 235 | void SendInquiryResponse( int id ); 236 | 237 | /** 238 | * @brief Send a JOIN request unicast. 239 | * @param[in] id Identifier of the target node. 240 | */ 241 | void SendJoinRequest( int id ); 242 | 243 | /** 244 | * @brief Send a JOIN response unicast. 245 | * @param[in] id Identifier of the target node. 246 | */ 247 | void SendJoinResponse( int id ); 248 | 249 | /** 250 | * @brief Send a JOIN denial unicast. 251 | * @param[in] id Identifier of the target node. 252 | */ 253 | void SendJoinDenial( int id ); 254 | 255 | /** 256 | * @brief Send a POLL unicast to all CMs. 257 | */ 258 | void PollClusterMembers(); 259 | 260 | /** 261 | * @brief Respond to a POLL unicast. 262 | */ 263 | void AcknowledgePoll( int id ); 264 | 265 | /** 266 | * @brief Tell edge nodes to broadcast the cluster presence frame. 267 | */ 268 | void OrderClusterPresenceBroadcast(); 269 | 270 | /** 271 | * @brief Broadcast the cluster presence frame. 272 | */ 273 | void BroadcastClusterPresence(); 274 | 275 | /** 276 | * @brief Send a cluster unification request. 277 | */ 278 | void RequestClusterUnification( int id ); 279 | 280 | /** 281 | * @brief Send a cluster unification response. 282 | */ 283 | void SendUnificationResponse( int id, int role ); 284 | 285 | /** 286 | * @brief Leave the cluster. 287 | */ 288 | void LeaveCluster(); 289 | 290 | 291 | /** 292 | * @brief Calculate the Link Expiration Time. 293 | * @param[in] pos Position of the target node. 294 | * @param[in] vel Velocity of the target node. 295 | * @return The time until the link expires. 296 | */ 297 | 298 | double CalculateLinkExpirationTime( Coord pos, Coord vel ); 299 | 300 | /** 301 | * Update neighbour data with the given message. 302 | */ 303 | void UpdateNeighbour( RmacControlMessage *m ); 304 | 305 | /*@}*/ 306 | 307 | 308 | //unsigned int mId; /**< The identifier of this node. */ 309 | ClusterState mCurrentState; /**< This is the current state of the node. */ 310 | 311 | NeighbourTable mNeighbours; /**< This node's neighbour table. */ 312 | 313 | NodeIdSet mWaitingPollAcks; /**< IDs of nodes we're awaiting poll responses from. */ 314 | 315 | double mTransmitRangeSq; /**< Transmission range, squared. */ 316 | double mZoneOfInterest; /**< This is double the TX range. Obtained from the PhyLayer module. */ 317 | 318 | bool mInitialised; /**< Set to true if the init function has been called. */ 319 | 320 | 321 | /** 322 | * @name Messages 323 | * @brief Messages this module sends itself. 324 | * 325 | * These are used for timed events. 326 | * 327 | **/ 328 | /*@{*/ 329 | 330 | cMessage *mFirstTimeProcess; /**< Scheduled when the cluster algorithm starts, to signal the first calling of the Process function. */ 331 | cMessage *mInquiryTimeoutMessage; /**< Scheduled for INQ timeout. */ 332 | cMessage *mInquiryResponseTimeoutMessage; /**< Scheduled for INQ_RESP timeout. */ 333 | cMessage *mJoinTimeoutMessage; /**< Scheduled for JOIN timeout. */ 334 | cMessage *mJoinDenyMessage; /**< Message to signify a JOIN request was denied. */ 335 | cMessage *mPollTriggerMessage; /**< Message to trigger a CH to poll its members. */ 336 | cMessage *mPollTimeoutMessage; /**< Scheduled by CMs and CHMs waiting for poll from their CH. */ 337 | cMessage *mPollPeriodFinishedMessage; /**< Message to signify end of poll period. */ 338 | cMessage *mClusterPresenceBeaconMessage; /**< Message to trigger beaconing of CLUSTER_PRESENCE. */ 339 | cMessage *mClusterUnifyTimeoutMessage; /**< Scheduled for timeout of a unify request. */ 340 | 341 | /*@}*/ 342 | 343 | 344 | /** 345 | * @name Parameters 346 | * @brief Module parameters. 347 | * 348 | * These are uses to configure the algorithm. 349 | * 350 | **/ 351 | /*@{*/ 352 | 353 | unsigned int mConnectionLimits; /**< Maximum number of connections this node can have. This is basically an upper limit on the size of the cluster. */ 354 | double mDistanceThreshold; /**< Distance threshold. */ 355 | double mTimeThreshold; /**< Time threshold. */ 356 | double mInquiryPeriod; /**< Period for INQ broadcasts. */ 357 | double mInquiryResponsePeriod; /**< Period during which INQ responses are collated. */ 358 | double mJoinTimeoutPeriod; /**< Period for JOIN timeout. */ 359 | double mPollInterval; /**< Period for CHs polling */ 360 | double mPollTimeout; /**< If a CM doesn't hear a POLL from the CH in this time, it departs the cluster. */ 361 | unsigned int mMissedPingThreshold; /**< Number of pings a node will miss before it is considered gone. */ 362 | 363 | /*@}*/ 364 | 365 | 366 | /** 367 | * @name Results 368 | * @brief Results to be recorded. 369 | * 370 | * These members record the performance of the algorithm. 371 | * The following performance metrics are recorded: 372 | * 1. Cluster Depth 373 | * This is the maximum number of levels reached by 374 | * a cluster while this node has served as its head. 375 | * Only CHs record this. 376 | * Type: Scalar 377 | * 378 | **/ 379 | /*@{*/ 380 | 381 | simsignal_t mSigClusterDepth; /**< ClusterDepth */ 382 | 383 | /*@}*/ 384 | 385 | 386 | 387 | /** 388 | * This implements the sorting mechanism for the Node Precidence Algorithm. 389 | */ 390 | struct NPA { 391 | bool operator()( const int&, const int& ); 392 | RmacNetworkLayer *mClient; 393 | }; 394 | 395 | NodeIdSet mTemporaryClusterRecord; /**< When a node receives a SEND_CLUSTER_PRESENCE_MESSAGE, it stores the cluster member record here. */ 396 | NodeIdList mClusterHierarchy; /**< List of heads of clusters within the hierarchy. This is used to prevent cyclical clusters. */ 397 | std::map mLevelLookup; /**< Lookup table of node IDs and the corresponding depth of their branches in the hierarchy. */ 398 | int mMaximumLevels; /**< Length of the longest branch at this point in the hierarchy. */ 399 | int mCurrentLevels; /**< The largest length this cluster has ever reached. */ 400 | 401 | void UpdateLevelOfMember( int id, NodeIdList& record, bool eraseThis=false ); 402 | 403 | }; 404 | 405 | 406 | #define MapHasKey(map,key) ( map.find(key) != map.end() ) 407 | #define ListHasValue(l,v) ( std::find(l.begin(),l.end(),v) != l.end() ) 408 | 409 | #endif /* RMACNETWORKLAYER_H_ */ 410 | -------------------------------------------------------------------------------- /src/RmacNetworkLayer.ned: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | package clusterlib; 17 | 18 | import org.mixim.base.modules.BaseNetwLayer; 19 | 20 | // 21 | // This module implements the clustering mechanism for 22 | // Robust Mobility-Aware Clustering (RMAC). 23 | // 24 | simple RmacNetworkLayer extends BaseNetwLayer 25 | { 26 | parameters: 27 | @class(RmacNetworkLayer); 28 | 29 | int connectionLimits; // Maximum number of connections this node can have. This is basically an upper limit on the size of the cluster. 30 | double distanceThreshold @unit("m"); // Distance threshold. 31 | double timeThreshold @unit("s"); // Time threshold. 32 | double inquiryPeriod @unit("s"); // Period for INQ broadcasts. 33 | double inquiryResponsePeriod @unit("s"); // Period during which INQ responses are collated. 34 | double joinTimeoutPeriod @unit("s"); // Period for JOIN timeout. 35 | double pollInterval @unit("s"); // Polling interval. 36 | double pollTimeout @unit("s"); // Polling timeout. 37 | int missedPingThreshold; // Maximum number of missed pings before a CM is declared dead. 38 | 39 | // signals 40 | @signal[sigOverhead](type="int"); 41 | @signal[sigHelloOverhead](type="int"); 42 | @signal[sigClusterLifetime](type="double"); 43 | @signal[sigClusterSize](type="int"); 44 | @signal[sigHeadChange](type="int"); 45 | @signal[sigDeathType](type="int"); 46 | @signal[sigDeathX](type="double"); 47 | @signal[sigDeathY](type="double"); 48 | @signal[sigClusterDepth](type="int"); 49 | 50 | // statistics 51 | @statistic[ overhead]( source = sigOverhead; record = stats; title = "Overhead per node"; unit = "bytes" ); 52 | @statistic[ helloOverhead]( source = sigHelloOverhead; record = stats; title = "Overhead per node (HELLO messages)"; unit = "bytes" ); 53 | @statistic[clusterLifetime]( source = sigClusterLifetime; record = stats; title = "Cluster Lifetime"; unit = "s" ); 54 | @statistic[ clusterSize]( source = sigClusterSize; record = stats; title = "Cluster Size"; ); 55 | @statistic[ headChange]( source = "count(sigHeadChange)"; record = last; title = "CH changes"; ); 56 | @statistic[ deathType]( source = sigDeathType; record = vector; title = "Cluster Death Types"; ); 57 | @statistic[ deathX]( source = sigDeathX; record = vector; title = "Cluster Death Position X"; ); 58 | @statistic[ deathY]( source = sigDeathY; record = vector; title = "Cluster Death Position Y"; ); 59 | @statistic[ clusterDepth]( source = sigClusterDepth; record = stats; title = "Cluster Depth"; ); 60 | 61 | 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/RouteSimilarityCluster.cc: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #include "BaseNetwLayer.h" 17 | 18 | //#include 19 | #include 20 | 21 | #include "NetwControlInfo.h" 22 | #include "BaseMacLayer.h" 23 | #include "AddressingInterface.h" 24 | #include "SimpleAddress.h" 25 | #include "FindModule.h" 26 | #include "MdmacControlMessage_m.h" 27 | #include "ArpInterface.h" 28 | #include "NetwToMacControlInfo.h" 29 | #include "BaseMobility.h" 30 | #include "BaseConnectionManager.h" 31 | #include "ChannelAccess.h" 32 | 33 | 34 | #include "TraCIScenarioManager.h" 35 | #include "TraCIMobility.h" 36 | 37 | #include "RouteSimilarityCluster.h" 38 | 39 | 40 | Define_Module(RouteSimilarityCluster); 41 | 42 | 43 | 44 | /** @brief Initialization of the module and some variables*/ 45 | void RouteSimilarityCluster::initialize( int stage ) { 46 | 47 | MdmacNetworkLayer::initialize( stage ); 48 | mIncludeDestination = true; 49 | if ( stage == 1 ) { 50 | 51 | mLinkCount = par("linkCount").longValue(); 52 | TraCIScenarioManager *pManager = TraCIScenarioManagerAccess().get(); 53 | std::string myId = dynamic_cast(mMobility)->getExternalId(); 54 | std::string myRouteId = pManager->commandGetRouteId( myId ); 55 | mRouteList = pManager->commandGetRouteEdgeIds( myRouteId ); 56 | 57 | // std::cerr << "Route:\n"; 58 | // for ( RouteLinkList::iterator it = mRouteList.begin(); it != mRouteList.end(); it++ ) 59 | // std::cerr << *it << ", "; 60 | // std::cerr << "\n"; 61 | 62 | 63 | } 64 | 65 | } 66 | 67 | 68 | 69 | 70 | /** Add the destination data to a packet. */ 71 | int RouteSimilarityCluster::AddDestinationData( MdmacControlMessage *pkt ) { 72 | 73 | // First check if the first id in the list is our current link. 74 | while ( mRoadID != mRouteList.front() ) 75 | mRouteList.erase( mRouteList.begin() ); 76 | 77 | // Check to make sure it didn't wipe the entire route list. 78 | if ( mRouteList.empty() ) { 79 | std::cerr << "STUB: node[" << mId << "] route end!\n"; 80 | return 0; 81 | } 82 | // 83 | // std::cerr << "Route:\n"; 84 | // for ( RouteLinkList::iterator it = mRouteList.begin(); it != mRouteList.end(); it++ ) 85 | // std::cerr << *it << ", "; 86 | // std::cerr << "\n"; 87 | 88 | // Now add at most 'mLinkCount' number of links to the packet. 89 | int size = 0; 90 | RouteLinkList::iterator myListStart = mRouteList.begin(); 91 | for ( int i = 0; i < std::min( mLinkCount, (int)mRouteList.size() ); i++ ) { 92 | 93 | std::string currEdge = *myListStart; 94 | pkt->getRoute().push_back( currEdge ); 95 | 96 | // Add the number of bits used to encode the edge name. 97 | size += currEdge.length()*8; 98 | 99 | myListStart++; 100 | 101 | } 102 | 103 | // Return the size. 104 | return size; 105 | 106 | } 107 | 108 | 109 | /** Store the destination data from a packet. */ 110 | void RouteSimilarityCluster::StoreDestinationData( MdmacControlMessage *m ) { 111 | 112 | mNeighbours[m->getNodeId()].mRouteLinks = m->getRoute(); 113 | 114 | } 115 | 116 | 117 | 118 | /** @brief Compute the CH weight for this node. */ 119 | double RouteSimilarityCluster::calculateWeight() { 120 | 121 | // This weight is the sum of percent route similarity between this node and its neighbours. 122 | // The node iterates through its neighbour table and checks the route links it has logged. 123 | // Starting from the beginning, the node adds 1/N to the weight for every matching link it finds. 124 | 125 | if ( !mMobility || mNeighbours.size() == 0 ) 126 | return 0; 127 | 128 | double mScore = 0; 129 | 130 | for ( NeighbourIterator it = mNeighbours.begin(); it != mNeighbours.end(); it++ ) { 131 | 132 | RouteLinkList::iterator myListStart = mRouteList.begin(); 133 | RouteLinkList::iterator theirListStart = it->second.mRouteLinks.begin(); 134 | 135 | // Start looking for match ups. 136 | for ( int i = 0; i < std::min( mLinkCount, std::min( (int)mRouteList.size(), (int)it->second.mRouteLinks.size() ) ); i++ ) { 137 | 138 | if ( *myListStart != *theirListStart ) 139 | break; // Mismatch between routes, so bail out. 140 | 141 | // Got a match, so add it to the weight. 142 | mScore++; 143 | myListStart++; 144 | theirListStart++; 145 | 146 | } 147 | 148 | } 149 | 150 | // mScore /= mLinkCount; 151 | // std::cerr << "Score(" << mId << ") = " << mScore << "\n"; 152 | return mScore; 153 | 154 | } 155 | -------------------------------------------------------------------------------- /src/RouteSimilarityCluster.h: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | #ifndef __CLUSTERLIB_AMACADWEIGHTCLUSTER_H_ 17 | #define __CLUSTERLIB_AMACADWEIGHTCLUSTER_H_ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include "MdmacControlMessage_m.h" 28 | #include "MdmacNetworkLayer.h" 29 | 30 | 31 | /** 32 | * Implements the Route Similarity Function Clustering metric. 33 | */ 34 | class RouteSimilarityCluster : public MdmacNetworkLayer 35 | { 36 | public: 37 | /** @brief Initialization of the module and some variables*/ 38 | virtual void initialize(int); 39 | 40 | protected: 41 | 42 | int mLinkCount; /**< Number of look-ahead links to use. */ 43 | RouteLinkList mRouteList; /**< List of route links. */ 44 | 45 | 46 | /** Add the destination data to a packet. */ 47 | int AddDestinationData( MdmacControlMessage *pkt ); 48 | 49 | /** Store the destination data from a packet. */ 50 | void StoreDestinationData( MdmacControlMessage *pkt ); 51 | 52 | /** @brief Compute the CH weight for this node. */ 53 | double calculateWeight(); 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/RouteSimilarityCluster.ned: -------------------------------------------------------------------------------- 1 | // 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU Lesser General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | // 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public License 13 | // along with this program. If not, see http://www.gnu.org/licenses/. 14 | // 15 | 16 | package clusterlib; 17 | 18 | // 19 | // Implements the Route Similarity Function Clustering metric. 20 | // 21 | simple RouteSimilarityCluster extends MdmacNetworkLayer 22 | { 23 | parameters: 24 | @class(RouteSimilarityCluster); 25 | int linkCount; 26 | } 27 | -------------------------------------------------------------------------------- /src/package.ned: -------------------------------------------------------------------------------- 1 | package clusterlib; 2 | 3 | @license(LGPL); 4 | -------------------------------------------------------------------------------- /tools/GenerateGrid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys, os, subprocess, random, math, numpy, csv 4 | from optparse import OptionParser 5 | import sumolib 6 | 7 | 8 | sumoConfigFormat = """ 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | """ 21 | 22 | 23 | launchdConfigFormat = """ 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | """ 32 | 33 | 34 | 35 | def CreateVehicleDefinitionXML( vDef ): 36 | vDefStr = "" 42 | return vDefStr 43 | 44 | 45 | def LoadVehicleDefinitions( fname ): 46 | vehicleDefinitions = [] 47 | with open( fname, "r" ) as f: 48 | r = csv.reader( f, delimiter=" " ) 49 | 50 | for line in r: 51 | vehicleDef = {} 52 | vehicleDef["id"] = line[0] 53 | vehicleDef["accel"] = line[1] 54 | vehicleDef["decel"] = line[2] 55 | vehicleDef["sigma"] = line[3] 56 | vehicleDef["length"] = line[4] 57 | vehicleDef["color"] = line[5] 58 | vehicleDef["width"] = line[6] 59 | vehicleDef["height"] = line[7] 60 | vehicleDef["weight"] = float(line[8]) 61 | vehicleDef["minGap"] = line[9] 62 | vehicleDefinitions.append( vehicleDef ) 63 | 64 | wSum = 0 65 | for vDef in vehicleDefinitions: 66 | wSum += vDef["weight"] 67 | if wSum != 1: 68 | for vDef in vehicleDefinitions: 69 | vDef["weight"] /= wSum 70 | 71 | print "Loaded " + str(len(vehicleDefinitions)) + " vehicle definitions." 72 | return vehicleDefinitions 73 | 74 | def PickRandomVehicleType( vehicleDefinitions ): 75 | if not vehicleDefinitions: 76 | return "typeWE" 77 | 78 | n = float( random.random() ) 79 | v = None 80 | for vDef in sorted( vehicleDefinitions, key=lambda v: v["weight"] ): 81 | if n < vDef["weight"]: 82 | v = vDef 83 | break 84 | else: 85 | n -= vDef["weight"] 86 | return v["id"] 87 | 88 | 89 | def parseOptions( argv ): 90 | optParser = OptionParser() 91 | optParser.add_option("-d", "--directory", dest="directory", help="Define the maps directory.") 92 | optParser.add_option("-L", "--lane.min", dest="minLanes", help="Minimum number of lanes.", type = "int", default=1 ) 93 | optParser.add_option("-l", "--lane.max", dest="maxLanes", help="Maximum number of lanes.", type = "int", default=4 ) 94 | optParser.add_option("-S", "--runTime", dest="runTime", help="Time taken for a car to traverse.", type = "int", default=900 ) 95 | optParser.add_option("-j", "--junction.min", dest="minJunction", help="Minimum number of junctions.", type = "int", default=0 ) 96 | optParser.add_option("-J", "--junction.max", dest="maxJunction", help="Maximum number of junctions.", type = "int", default=5 ) 97 | optParser.add_option("-p", "--cornerPath", dest="cornerPath", help="Directory of the CORNER classifier." ) 98 | optParser.add_option("-c", "--clusterPath", dest="clusterPath", help="Directory of the ClusterLib tools." ) 99 | optParser.add_option("-C", "--cbdRoutePath", dest="cbdRoutePath", help="Directory of the CBDRouter tool." ) 100 | optParser.add_option("-V", "--vehicleTypes", dest="vehicleTypes", help="Vehicle type definition file." ) 101 | optParser.add_option("-R", "--route-number", dest="routeNumber", help="Number of routes to generate.", type = "int", default=250 ) 102 | optParser.add_option("-t", "--maximum-time", dest="maxTime", help="The time limit of the simulation.", type = "int", default=2000 ) 103 | optParser.add_option("-D", "--do-reverse", dest="doReverse", help="Create a reverse of each route.", default=False, action='store_true' ) 104 | optParser.add_option("-H", "--highway", dest="highway", help="Do a highway.", default=False, action='store_true' ) 105 | optParser.add_option("-a", "--speed.min", dest="minSpeed", help="Minimum Highway speed (km/h).", type = "int", default=40 ) 106 | optParser.add_option("-A", "--speed.max", dest="maxSpeed", help="Maximum Highway speed (km/h).", type = "int", default=120 ) 107 | optParser.add_option("-f", "--speed.step", dest="stepSpeed", help="Highway speed step (km/h).", type = "int", default=20 ) 108 | optParser.add_option("-v", "--minCarNumber", dest="minVehicleNumber", help="Minimum car density per tx range.", type = "float", default=1 ) 109 | optParser.add_option("-y", "--maxCarNumber", dest="maxVehicleNumber", help="Maximum car density per tx range.", type = "float", default=10 ) 110 | optParser.add_option("-Y", "--stepCarNumber", dest="stepVehicleNumber", help="Vehicle increment.", type = "float", default=1 ) 111 | optParser.add_option("-m", "--speedvar.min", dest="minSpeedVariance", help="Minimum variance in speed.", type = "float", default=0 ) 112 | optParser.add_option("-M", "--speedvar.max", dest="maxSpeedVariance", help="Maximum variance in speed.", type = "float", default=0.2 ) 113 | optParser.add_option("-Z", "--speedvar.step", dest="stepSpeedVariance", help="Speed variance step.", type = "float", default=0.05 ) 114 | optParser.add_option("-r", "--transmitRange", dest="transmitRange", help="Vehicle transmission range.", type = "float", default=100 ) 115 | optParser.add_option("-w", "--laneWidth", dest="laneWidth", help="Lane width.", type = "float", default=2.5 ) 116 | optParser.add_option("-b", "--turnProbability", dest="turnProbability", help="Probability of a car turning.", type = "float", default=0.5 ) 117 | optParser.add_option("-B", "--filePrefix", dest="filePrefix", help="Generated file prefix.", type = "string" ) 118 | optParser.add_option("-q", "--randomSeed", dest="randomSeed", help="Random seed to set.", type = "int" ) 119 | (options, args) = optParser.parse_args(argv) 120 | 121 | if not options.directory: 122 | print "Please specify results directory." 123 | optParser.print_help() 124 | sys.exit() 125 | 126 | if options.randomSeed: 127 | random.seed( options.randomSeed ) 128 | 129 | return options 130 | 131 | 132 | 133 | 134 | def generateGrids( options ): 135 | fileList = [] 136 | for laneCount in range( options.minLanes, options.maxLanes+1, options.stepLanes ): 137 | for roadLength in range( options.minRoads, options.maxRoads+1, options.stepRoads ): 138 | filename = "grid-" + str(options.junctionCount) + "x" + str(options.junctionCount) + "-" + str(laneCount) + "lane-" + str(roadLength) + "m" 139 | print "Generating '" + filename + "'..." 140 | p = subprocess.Popen( ['netgen','-g','--grid.number',str(options.junctionCount),'--grid.length',str(roadLength),'-L',str(laneCount),'--no-internal-links','--tls.guess','-o',filename+".net.xml"] ) 141 | p.wait() 142 | 143 | cbdFile = filename + '.cbd' 144 | with open(cbdFile,'w') as f: 145 | f.write("0,0,"+str(roadLength)+"\n") 146 | w = str((options.junctionCount-1)*roadLength) 147 | f.write(w+","+w+","+str(roadLength)+"\n") 148 | 149 | fileList.append( [ filename, laneCount, roadLength ] ) 150 | 151 | return fileList 152 | 153 | 154 | 155 | def generateHighway( junctionCount, roadLength, laneCount, speed, filename ): 156 | # First create node file 157 | with open( filename+".nod.xml", "w" ) as f: 158 | f.write("\n") 159 | f.write("\n") 160 | for c in range(0,junctionCount+2): 161 | f.write("\t\n") 162 | if c > 0 and c < junctionCount+1: 163 | f.write("\t\n") 164 | f.write("\t\n") 165 | f.write("\n") 166 | 167 | # Next create edge file 168 | with open( filename+".edg.xml", "w" ) as f: 169 | f.write("\n") 170 | f.write("\n") 171 | for c in range(0,junctionCount+1): 172 | f.write("\t\n") 173 | if c > 0 and c < junctionCount+1: 174 | l = laneCount / 2 175 | if l == 0: 176 | l = 1 177 | f.write("\t\n") 178 | f.write("\t\n") 179 | f.write("\n") 180 | 181 | # Convert the files to net.xml 182 | p = subprocess.Popen( ['netconvert','-n',filename+'.nod.xml','-e',filename+'.edg.xml','-o',filename+'.net.xml','--no-internal-links'] ) 183 | p.wait() 184 | 185 | # Remove the temp files. 186 | os.remove( filename+".nod.xml" ) 187 | os.remove( filename+".edg.xml" ) 188 | return filename+".net.xml" 189 | 190 | 191 | 192 | def generateHighways( options ): 193 | fileList = [] 194 | for laneCount in range( options.minLanes, options.maxLanes+1, 1 ): 195 | for junctionCount in range( options.minJunction, options.maxJunction+1, 1 ): 196 | for speed in range( options.minSpeed, options.maxSpeed+1, options.stepSpeed ): 197 | for var in numpy.arange( options.minSpeedVariance, options.maxSpeedVariance+options.stepSpeedVariance/2, options.stepSpeedVariance ): 198 | roadLength = options.runTime * speed / ( 3.6 * ( junctionCount + 1 ) ) 199 | if options.filePrefix: 200 | filename = options.filePrefix 201 | else: 202 | filename = "highway-" + str(junctionCount) + "-" + str(laneCount) + "lane-" + str(speed) + "kmph" 203 | print "Generating '" + filename + "'..." 204 | generateHighway( junctionCount, roadLength, laneCount, speed / 3.6, filename ) 205 | fileList.append( [filename, laneCount, roadLength, speed, junctionCount, str(var)] ) 206 | 207 | return fileList 208 | 209 | 210 | 211 | def generateHighwayRoutes( filename, roadLength, vehicleRate, junctionCount, laneCount, speed, speedVar, options ): 212 | # Load vehicle types 213 | vTypes = LoadVehicleDefinitions( options.vehicleTypes ) 214 | 215 | carRate = 2 * speed * vehicleRate / ( 3.6 * options.transmitRange * laneCount ) 216 | 217 | if options.filePrefix: 218 | tempFileName = options.filePrefix + ".trip" 219 | else: 220 | tempFileName = filename + "-" + str(vehicleRate) + ".trip" 221 | 222 | # Load the highway maps 223 | net = sumolib.net.readNet(filename+'.net.xml') 224 | 225 | destinationLookup = {} 226 | 227 | with open( tempFileName, "w" ) as f: 228 | f.write( '\n' ) 229 | 230 | f.write( '\n' ) 231 | 232 | # Write the definitions 233 | for t in vTypes: 234 | t['speedDev'] = speedVar 235 | f.write( "\t" + CreateVehicleDefinitionXML( t ) + '\n' ) 236 | 237 | genPeriod = math.ceil( 1/carRate ) 238 | numGen = 1 239 | if genPeriod <= 1: 240 | genPeriod = 1 241 | numGen = int( math.ceil( carRate ) ) 242 | 243 | lastGen = -genPeriod 244 | ID = 0 245 | for t in range(0,options.maxTime): 246 | if ( t - lastGen ) == genPeriod: 247 | for n in range(0,numGen): 248 | turnOff = junctionCount > 0 249 | sinkIndex = None 250 | if turnOff: 251 | for n in range(1,junctionCount+1): 252 | if numpy.random.random() < options.turnProbability: 253 | sinkIndex = n 254 | break 255 | if not sinkIndex: 256 | turnOff = False 257 | 258 | if turnOff: 259 | sinkEdge = str(sinkIndex) 260 | if random.randint(0,1) == 1: 261 | sinkEdge += "_goup" 262 | else: 263 | sinkEdge += "_godown" 264 | else: 265 | sinkEdge = str(junctionCount) + "_" + str(junctionCount+1) 266 | ID += 1 267 | destinationLookup["car_"+str(ID)] = [ options.maxTime ] + net.getEdge( sinkEdge )._to._coord 268 | f.write( '\n'.format( ID, t, sinkEdge, PickRandomVehicleType(vTypes) ) ) 269 | lastGen = t 270 | f.write( '\n' ) 271 | 272 | if options.filePrefix: 273 | outputFilename = options.filePrefix + ".rou.xml" 274 | else: 275 | outputFilename = filename + "-" + str(vehicleRate) + "cars.rou.xml" 276 | p = subprocess.Popen( ['duarouter','-n',filename+'.net.xml','-t',tempFileName,'-o',outputFilename] ) 277 | p.wait() 278 | os.remove(tempFileName) 279 | 280 | # Dump a destination lookup for each node. 281 | with open(outputFilename+".dest","w") as f: 282 | f.write( str( len( destinationLookup ) ) + "\n" ) 283 | for car in destinationLookup: 284 | f.write( car + " 1\n" ) 285 | f.write( str( destinationLookup[car][0] ) + " " + str( destinationLookup[car][1] ) + " " + str( destinationLookup[car][2] ) + "\n" ) 286 | 287 | 288 | def analyseFiles( fileList, options ): 289 | for f in fileList: 290 | netFile = f[0]+'.net.xml' 291 | print "Running CORNER on '" + f[0] + "'..." 292 | p = subprocess.Popen( ['python',options.cornerPath+'/Sumo2Corner.py','-n',netFile] ) 293 | p.wait() 294 | print "Running LSUF on '" + f[0] + "'..." 295 | p = subprocess.Popen( ['python',options.clusterPath+'/LaneWeight.py','-n',netFile] ) 296 | p.wait() 297 | 298 | for carDensity in numpy.arange( options.minVehicleNumber, options.maxVehicleNumber+options.stepVehicleNumber, options.stepVehicleNumber ): 299 | if options.filePrefix: 300 | baseFile = options.filePrefix 301 | else: 302 | baseFile = f[0] + "-" + str(carDensity) + "cars" 303 | rouFile = baseFile + ".rou.xml" 304 | print "Generating route file '" + rouFile + "'..." 305 | 306 | if options.highway: 307 | generateHighwayRoutes( f[0], f[2], carDensity, f[4], f[1], f[3], f[5], options ) 308 | 309 | else: 310 | genCmd = ['python',options.cbdRoutePath+'/CBDRouter.py'] 311 | genCmd += ['-n',netFile] 312 | genCmd += ['-r',rouFile] 313 | genCmd += ['-V',options.vehicleTypes] 314 | genCmd += ['-v',str(carDensity)] 315 | genCmd += ['-R',str(options.routeNumber)] 316 | genCmd += ['-C',f[0]+'.cbd'] 317 | genCmd += ['-t',str(options.maxTime)] 318 | 319 | if options.doReverse: 320 | genCmd += ['-d'] 321 | p = subprocess.Popen( genCmd ) 322 | p.wait() 323 | 324 | with open( baseFile+".sumo.cfg", "w" ) as fout: 325 | fout.write( sumoConfigFormat.format( netFile, rouFile, 0, options.maxTime ) ) 326 | with open( baseFile+".launchd.xml", "w" ) as fout: 327 | fout.write( launchdConfigFormat.format( options.directory, netFile, rouFile, baseFile+".sumo.cfg" ) ) 328 | 329 | 330 | if __name__ == "__main__": 331 | options = parseOptions( sys.argv ) 332 | os.chdir( options.directory ) 333 | if options.highway: 334 | analyseFiles( generateHighways( options ), options ) 335 | else: 336 | analyseFiles( generateGrids( options ), options ) 337 | 338 | -------------------------------------------------------------------------------- /tools/LaneWeight.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sumolib 4 | from VectorMath import * 5 | from optparse import OptionParser 6 | 7 | def ComputeWeights( options ): 8 | 9 | netFile = sumolib.net.readNet( options.netFile ) 10 | laneWeights = [] 11 | 12 | # scan the edges in the net. 13 | netEdges = netFile.getEdges() 14 | for edge in netEdges: 15 | linkLookup = {} 16 | flows = {} 17 | flowLanePair = {} 18 | 19 | # Get a list of all outgoing connctions from this edge 20 | conns = [] 21 | outgoingConnections = edge.getOutgoing() 22 | for connection in outgoingConnections.iterkeys(): 23 | conns += outgoingConnections[connection] 24 | 25 | # If there are no outgoing connections, skip this edge. 26 | if len(conns) == 0: 27 | for i in range(0,edge.getLaneNumber()): 28 | laneWeights.append( [edge.getLane(i).getID(), 1.0, 0] ) 29 | continue 30 | 31 | # Scan the connections in the list. 32 | for connection in conns: 33 | # Get the ID of the destination link 34 | dest = connection._to._id 35 | 36 | # Add this to the link look-up 37 | if dest not in linkLookup: 38 | linkLookup[dest] = connection._to 39 | 40 | # Add the source lane to the flow-lane lookup. 41 | src = connection._fromLane.getID() 42 | if src not in flowLanePair.keys(): 43 | flowLanePair[src] = [] 44 | 45 | # Add this flow to the set of flows to which this lane belongs. 46 | flowLanePair[src].append(dest) 47 | 48 | # Remove duplicate flow entries for each lane, sort them, and produce a unique string ID for each flow. 49 | # For each unique ID, increment a counter in 'flows.' 50 | for lane in flowLanePair.iterkeys(): 51 | flowLanePair[lane] = str( sorted( list( set( flowLanePair[lane] ) ) ) ) 52 | if flowLanePair[lane] not in flows.keys(): 53 | flows[flowLanePair[lane]] = [0,len(flows.keys())] 54 | flows[flowLanePair[lane]][0] += 1 55 | 56 | # Now we've determined the flow each lane belongs to, we compute the lane weight, and add it to the list of weights 57 | for lane in flowLanePair.iterkeys(): 58 | flow = flowLanePair[lane] 59 | laneWeights.append( [ lane, float(flows[flow][0])/edge.getLaneNumber(), flows[flow][1] ] ) 60 | 61 | # Got all the weights. 62 | # Now we save the data to a file. 63 | print "Saving weights to " + options.outFile 64 | f = open( options.outFile, "w" ) 65 | f.write( str(len(laneWeights)) + "\n" ) 66 | for lane in laneWeights: 67 | f.write( lane[0] + " " + str(lane[1]) + " " + str(lane[2]) + "\n" ) 68 | f.close() 69 | 70 | 71 | def ParseOptions(): 72 | optParser = OptionParser() 73 | optParser.add_option("-o", "--out-file", dest="outFile", help="Define the output file.") 74 | optParser.add_option("-n", "--net-file", dest="netFile", help="Define the SUMO net file (manditory)") 75 | (options, args) = optParser.parse_args() 76 | 77 | if not options.netFile: 78 | optParser.print_help() 79 | sys.exit() 80 | 81 | if not options.outFile: 82 | options.outFile = options.netFile.split(".net.")[0] + ".lsuf" 83 | 84 | return options 85 | 86 | 87 | if __name__ == "__main__": 88 | ComputeWeights( ParseOptions() ) 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /tools/OmnetReader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os, numpy 4 | from VectorMath import * 5 | import subprocess 6 | 7 | class VersionException(Exception): 8 | def __init__(self,receivedVersionNumber): 9 | Exception.__init__(self,"Invalid result file version") 10 | self.receivedVersionNumber = receivedVersionNumber 11 | 12 | class Scalar: 13 | def __init__(self,name,moduleName,value): 14 | self.name = name 15 | self.moduleName = moduleName 16 | self.value = value 17 | self.attributes = {} 18 | 19 | class Statistic: 20 | def __init__(self,name,moduleName): 21 | self.name = name 22 | self.moduleName = moduleName 23 | self.fields = {} 24 | self.attributes = {} 25 | 26 | class Vector: 27 | def __init__(self,vectorId,name,moduleName,paramOrder,parentRun): 28 | self.vectorId = vectorId 29 | self.name = name 30 | self.moduleName = moduleName 31 | self.paramOrder = paramOrder 32 | self.indexData = [] 33 | self.attributes = {} 34 | self.parentRun = parentRun 35 | 36 | def addIndexData( self, blockOffset, blockLength ): 37 | self.indexData.append( [ blockOffset, blockLength ] ) 38 | 39 | def getVectorData(self): 40 | vectorData = [] 41 | fileName = self.parentRun.directory+"/"+self.parentRun.configName+"-"+str(self.parentRun.runId)+".vec" 42 | f = open(fileName, "r") 43 | for i in sorted(self.indexData, key=lambda tup: tup[0]): 44 | f.seek(i[0],0) 45 | data = f.read(i[1]) 46 | for line in data.split("\n"): 47 | l = line.split() 48 | if len(l) == 0: 49 | continue 50 | d = [0,0,0] 51 | for i in range(0,3): 52 | try: 53 | if self.paramOrder[i] == 'E': 54 | d[0] = int(l[i+1]) 55 | elif self.paramOrder[i] == 'T': 56 | d[1] = float(l[i+1]) 57 | elif self.paramOrder[i] == 'V': 58 | d[2] = float(l[i+1]) 59 | except IndexError: 60 | print l 61 | raise IndexError 62 | vectorData.append(d) 63 | return numpy.array( vectorData ) 64 | 65 | class Run: 66 | def __init__(self,runId,configName,directory): 67 | self.runId = runId 68 | self.configName = configName 69 | self.directory = directory 70 | self.loadScalars() 71 | self.loadVectors() 72 | 73 | def loadScalars(self): 74 | foundRun = False 75 | lastData = None 76 | lastScalar = None 77 | 78 | self.scalars = {} # module names are used as keys here 79 | self.statistics = {} 80 | self.scalarIndices = [] 81 | self.statisticsIndices = [] 82 | self.runAttributes = {} 83 | 84 | fileName = self.directory+"/"+self.configName+"-"+str(self.runId)+".sca" 85 | lineIndex = 0 86 | with open(fileName, "r") as f: 87 | for line in f: 88 | try: 89 | # parse the current line 90 | lineIndex += 1 91 | data = line.split() 92 | if len(data) == 0: 93 | continue 94 | if data[0] == "version": 95 | self.version = int(data[1]) 96 | if self.version != 2: 97 | raise VersionException(self.version) 98 | 99 | elif data[0] == "run": 100 | if foundRun: 101 | raise Exception("Run defined multiple times in '"+fileName+"'") 102 | foundRun = True 103 | lastData = "run" 104 | 105 | elif data[0] == "attr": 106 | if data[1] == '""': 107 | continue # Skip empties 108 | if lastData == "run": 109 | attrStr = "" 110 | for a in data[2:len(data)]: 111 | attrStr += a 112 | attrStr = attrStr.translate(None,'"\\') 113 | self.runAttributes[data[1]] = attrStr 114 | elif lastData == "scalar": 115 | self.scalars[lastScalar.moduleName][lastScalar.name].attributes[data[1]] = data[2] 116 | elif lastData == "statistic": 117 | self.statistics[lastScalar.moduleName][lastScalar.name].attributes[data[1]] = data[2] 118 | else: 119 | raise Exception("Unknown attribute '"+data[1]+"' at line "+str(lineIndex)+" in '"+fileName+"'") 120 | elif data[0] == "scalar": 121 | moduleName = data[1] 122 | scalarName = data[2].split(":")[0] 123 | scalarValue = float(data[3]) 124 | if not moduleName in self.scalars.keys(): 125 | self.scalars[moduleName] = {} 126 | else: 127 | if scalarName in self.scalars[moduleName].keys(): 128 | raise Exception("Scalar '"+moduleName+"/"+scalarName+"' redefined at line "+str(lineIndex)+" in '"+fileName+"'") 129 | self.scalars[moduleName][scalarName] = Scalar(scalarName,moduleName,scalarValue) 130 | lastScalar = self.scalars[moduleName][scalarName] 131 | lastData = "scalar" 132 | self.scalarIndices.append( [moduleName, scalarName] ) 133 | elif data[0] == "statistic": 134 | moduleName = data[1] 135 | statisticName = data[2].split(":")[0] 136 | if not moduleName in self.statistics.keys(): 137 | self.statistics[moduleName] = {} 138 | else: 139 | if statisticName in self.statistics[moduleName].keys(): 140 | raise Exception("Statistic '"+moduleName+"/"+scalarName+"' redefined at line "+str(lineIndex)+" in '"+fileName+"'") 141 | self.statistics[moduleName][statisticName] = Statistic(statisticName,moduleName) 142 | lastScalar = self.statistics[moduleName][statisticName] 143 | lastData = "statistic" 144 | self.statisticsIndices.append( [moduleName, statisticName] ) 145 | elif data[0] == "field": 146 | if lastData is not "statistic": 147 | raise Exception("Found field '" + data[1] + "' without statistic at line "+str(lineIndex)+" in '"+fileName+"'") 148 | if data[1] in self.statistics[lastScalar.moduleName][lastScalar.name].fields: 149 | raise Exception("Statistic field '" + data[1] + "' redefined at line "+str(lineIndex)+" in '"+fileName+"'") 150 | self.statistics[lastScalar.moduleName][lastScalar.name].fields[data[1]] = float(data[2]) 151 | 152 | except IndexError: 153 | print "IndexError exception raised at line " + str(lineIndex) + " in file " + fileName + " (" + line + ")" 154 | 155 | def loadVectors(self): 156 | foundRun = False 157 | lastData = None 158 | lastVector = None 159 | 160 | self.vectors = {} # module names are used as keys here 161 | self.vectorIndices = {} # contains tuples of moduleName,vectorName. VectorId used as keys 162 | 163 | fileName = self.directory+"/"+self.configName+"-"+str(self.runId)+".vci" 164 | lineIndex = 0 165 | with open(fileName, "r") as f: 166 | for line in f: 167 | try: 168 | lineIndex += 1 169 | # parse the current line 170 | data = line.split() 171 | 172 | if len(data) == 0: 173 | continue 174 | if data[0] == "version": 175 | self.version = int(data[1]) 176 | if self.version != 2: 177 | raise VersionException(self.version) 178 | 179 | elif data[0] == "run": 180 | if foundRun: 181 | raise Exception("Run defined multiple times in '"+fileName+"'") 182 | foundRun = True 183 | lastData = "run" 184 | 185 | elif data[0] == "attr": 186 | if data[1] == '""': 187 | continue # Skip empties 188 | if lastData == "run": 189 | pass 190 | elif lastData == "vector": 191 | self.vectors[lastVector.moduleName][lastVector.name].attributes[data[1]] = data[2] 192 | else: 193 | raise Exception("Unknown attribute '"+data[1]+"' at line "+str(lineIndex)+" in '"+fileName+"'") 194 | 195 | elif data[0] == "vector": 196 | vectorNumber = int(data[1]) 197 | vectorModule = data[2] 198 | vectorName = data[3] 199 | if not vectorModule in self.vectors.keys(): 200 | self.vectors[vectorModule] = {} 201 | else: 202 | if vectorName in self.vectors[vectorModule].keys(): 203 | raise Exception("Vector '"+vectorModule+"/"+vectorName+"' redefined at line "+str(lineIndex)+" in '"+fileName+"'") 204 | 205 | self.vectors[vectorModule][vectorName] = Vector( vectorNumber, vectorName, vectorModule, data[4], self ) 206 | lastVector = self.vectors[vectorModule][vectorName] 207 | lastData = "vector" 208 | self.vectorIndices[vectorNumber] = (vectorModule,vectorName) 209 | 210 | elif data[0].isdigit(): 211 | vectorNumber = int(data[0]) 212 | v = self.vectorIndices[vectorNumber] 213 | blockOffset = int(data[1]) 214 | blockLength = int(data[2]) 215 | self.vectors[v[0]][v[1]].addIndexData( blockOffset, blockLength ) 216 | 217 | except IndexError: 218 | print "IndexError exception raised at line " + str(lineIndex) + " in file " + fileName 219 | 220 | 221 | class DataContainer: 222 | 223 | def __init__(self,configName,directory,useTar=False): 224 | self.useTar = useTar 225 | self.configName = configName 226 | self.directory = directory 227 | self.loadRuns() 228 | self.currentRun = None 229 | 230 | def loadRuns(self): 231 | # Get all the run numbers 232 | if not self.useTar: 233 | self.runList = [ int( file[file.rfind("-")+1:file.rfind(".")] ) for file in os.listdir(self.directory) if self.configName in file and "sca" in file ] 234 | else: 235 | self.runList = [ int( file[file.find("-")+1:file.find(".tar")] ) for file in os.listdir(self.directory) if self.configName in file and "tar" in file ] 236 | 237 | # get list of files matching the config name 238 | #fileList = [ file for file in os.listdir(self.directory) if self.configName in file and "sca" in file ] 239 | #print self.configName + ": " + str(len(fileList)) + " runs found." 240 | #self.runs = {} 241 | #for f in fileList: 242 | #runId = int( f[f.rfind("-")+1:f.rfind(".")] ) 243 | #self.runs[runId] = Run(runId,self.configName,self.directory) 244 | 245 | def getRunList(self): 246 | return self.runList 247 | 248 | def selectRun(self,runNumber): 249 | loc = self.directory 250 | if self.useTar: 251 | subprocess.Popen( ['tar','-xf',self.directory+self.configName+'-'+str(runNumber)+'.tar.xz'] ).wait() 252 | loc = "results" 253 | hasError = False 254 | try: 255 | self.currentRun = Run(runNumber,self.configName,loc) 256 | except ValueError: 257 | hasError = True 258 | if self.useTar: 259 | subprocess.Popen( ['rm','-r','results'], stdout=subprocess.PIPE, stderr=subprocess.PIPE ).wait() 260 | if hasError: 261 | raise Exception( "Run data has errors." ) 262 | #self.currentRun = runNumber 263 | 264 | def getSelectedRun(self): 265 | return self.currentRun 266 | #return self.runs[self.currentRun] 267 | 268 | def findModule(self,moduleName): 269 | # this tries to locate an entry in the data container corresponding to the module name 270 | return [mod for mod in self.currentRun.scalars.iterkeys() if moduleName in mod] 271 | 272 | def getRunAttributes(self): 273 | if self.currentRun == None: 274 | raise Exception( "Asked for run attributes when no run has been selected." ) 275 | return self.currentRun.runAttributes 276 | 277 | def getVectorList(self): 278 | if self.currentRun == None: 279 | raise Exception( "Asked for vector list when no run has been selected." ) 280 | return self.currentRun.vectorIndices.values() 281 | 282 | def getVector(self,moduleName,vectorName): 283 | if self.currentRun == None: 284 | raise Exception( "Asked for vector data when no run has been selected." ) 285 | return self.currentRun.vectors[moduleName][vectorName].getVectorData() 286 | 287 | def getScalarList(self): 288 | if self.currentRun == None: 289 | raise Exception( "Asked for scalar list when no run has been selected." ) 290 | return self.currentRun.scalarIndices 291 | 292 | def getScalar(self,moduleName,scalarName): 293 | if self.currentRun == None: 294 | raise Exception( "Asked for scalar data when no run has been selected." ) 295 | return self.currentRun.scalars[moduleName][scalarName] 296 | 297 | def getStatisticsList(self): 298 | if self.currentRun == None: 299 | raise Exception( "Asked for statistics list when no run has been selected." ) 300 | return self.currentRun.statisticsIndices 301 | 302 | def getStatistic(self,moduleName,statisticName): 303 | if self.currentRun == None: 304 | raise Exception( "Asked for statistics data when no run has been selected." ) 305 | return self.currentRun.statistics[moduleName][statisticName] 306 | 307 | 308 | def FindNearestTimeInVector(time,vec,lastIndex): 309 | diffMin = numpy.inf 310 | index = -1 311 | for i in range(lastIndex,len(vec)): 312 | d = numpy.abs(vec[i,1] - time) 313 | if d < diffMin: 314 | diffMin = d 315 | index = i 316 | else: 317 | break 318 | return index 319 | 320 | 321 | class kReader: 322 | def __init__(self,directory,granularity,fileName): 323 | # this reads all the results in the experiment and puts it into a tuppled database 324 | self.granularity = granularity 325 | self.baseDirectory = directory 326 | self.resultDirectory = self.baseDirectory + "/simulations/results/" 327 | self.ScanExperiments() 328 | self.powerResults = {} 329 | for location in self.locations.iterkeys(): 330 | self.powerResults[location] = {"staticK":{},"raytracing":{},"raytracing-cars":{}} 331 | self.Analyse(location) 332 | self.SaveToFile(fileName) 333 | 334 | def FindNearestTimeInVector(self,time,vec,lastIndex): 335 | diffMin = numpy.inf 336 | index = -1 337 | for i in range(lastIndex,len(vec)): 338 | d = numpy.abs(vec[i,1] - time) 339 | if d < diffMin: 340 | diffMin = d 341 | index = i 342 | return index 343 | 344 | def ScanExperiments(self): 345 | # first get all files in the directory 346 | fileList = [ file for file in os.listdir(self.resultDirectory) if "sca" in file ] 347 | # then construct data container for each configuration 348 | configs = [] 349 | self.locations = {} 350 | for f in fileList: 351 | c = f[0:f.rfind("-")] 352 | if not c in configs: 353 | configs.append(c) 354 | 355 | for c in configs: 356 | container = DataContainer( c, self.resultDirectory ) 357 | location = c.split("-")[1] 358 | if location not in self.locations.keys(): 359 | self.locations[location] = [] 360 | self.locations[location].append( container ) 361 | 362 | def Analyse(self,locationName): 363 | for location in self.locations[locationName]: 364 | runs = location.getRunList() 365 | for run in runs: 366 | location.selectRun(run) 367 | if location.getScalar("rsu_scenario.node[0].nic.phy","useRaytracer") == 1: 368 | expType = "raytracing" 369 | if location.getScalar("rsu_scenario.node[0].nic.phy","useVehicles") == 1: 370 | expType = "raytracing-cars" 371 | expParam = float(location.getScalar("rsu_scenario.node[0].nic.phy","rayCount")[0]) 372 | else: 373 | expType = "staticK" 374 | expParam = float(location.getScalar("rsu_scenario.node[0].nic.phy","constantK")[0]) 375 | 376 | if not expParam in self.powerResults[locationName][expType]: 377 | self.powerResults[locationName][expType][expParam] = {} 378 | 379 | # Get receiver position for this run 380 | rxPosStr = location.getSelectedRun().runAttributes["iterationvars"] 381 | elems = rxPosStr.split(",") 382 | if "posX" in elems[0]: 383 | rxPosX = float(elems[0].split("=")[1]) 384 | rxPosY = float(elems[1].split("=")[1]) 385 | elif "posX" in elems[1]: 386 | rxPosX = float(elems[1].split("=")[1]) 387 | rxPosY = float(elems[2].split("=")[1]) 388 | else: 389 | raise Exception("Invalid run attribute 'iterationvars'") 390 | rxPos = ((round(rxPosX/self.granularity)*self.granularity), (round(rxPosY/self.granularity)*self.granularity)) 391 | 392 | if not rxPos in self.powerResults[locationName][expType][expParam]: 393 | self.powerResults[locationName][expType][expParam][rxPos] = {} 394 | 395 | # Get transmitter positions 396 | vecTxPosX = location.getVector("rsu_scenario.receiver.appl","positionX") 397 | vecTxPosY = location.getVector("rsu_scenario.receiver.appl","positionY") 398 | rxPower = location.getVector("rsu_scenario.receiver.nic","RcvPower") 399 | lastTimePos = 0 400 | print "Processing...", 401 | for i in range(0,len(vecTxPosX)): 402 | currPos = ((round(vecTxPosX[i,2]/self.granularity)*self.granularity), (round(vecTxPosY[i,2]/self.granularity)*self.granularity)) 403 | if not currPos in self.powerResults[locationName][expType][expParam][rxPos]: 404 | self.powerResults[locationName][expType][expParam][rxPos][currPos] = [] 405 | nearIndex = self.FindNearestTimeInVector(vecTxPosX[i,1],rxPower,lastTimePos) 406 | self.powerResults[locationName][expType][expParam][rxPos][currPos] += list(rxPower[lastTimePos:nearIndex,2]) 407 | lastTimePos = nearIndex 408 | 409 | percentComplete = 100*i/float(len(vecTxPosX)) 410 | print "\rProcessing " + locationName + "-" + expType + "-" + str(run) + "... (%.2f percent complete)" % percentComplete, 411 | 412 | def SaveToFile(self,fileName): 413 | for locationName in self.locations.iterkeys(): 414 | f=open(locationName+"-"+fileName, 'w') 415 | pickle.dump(self.powerResults[locationName], f) 416 | f.close() 417 | 418 | 419 | 420 | 421 | --------------------------------------------------------------------------------