1/* Copyright (c) 2012 Massachusetts Institute of Technology 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to deal 5 * in the Software without restriction, including without limitation the rights 6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 * copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 * THE SOFTWARE. 20 */ 21 22 23#include "model/optical_graph/OpticalGraph.h" 24 25#include "model/OpticalModel.h" 26#include "model/optical_graph/OpticalNode.h" 27#include "model/optical_graph/OpticalLaser.h" 28#include "model/optical_graph/OpticalModulator.h" 29#include "model/optical_graph/OpticalFilter.h" 30#include "model/optical_graph/OpticalDetector.h" 31#include "model/optical_graph/OpticalWavelength.h" 32 33namespace DSENT 34{ 35 // Initialize the next visited number to be one above the initial number 36 // used by OpticalNode 37 int OpticalGraph::msTreeNum = OpticalNode::OPTICAL_NODE_INIT_VISITED_NUM + 1; 38 39 OpticalGraph::OpticalGraph(const String& instance_name_, OpticalModel* model_) 40 : m_instance_name_(instance_name_), m_model_(model_) 41 { 42 43 } 44 45 OpticalGraph::~OpticalGraph() 46 { 47 48 } 49 50 const String& OpticalGraph::getInstanceName() const 51 { 52 return m_instance_name_; 53 } 54 55 //------------------------------------------------------------------------- 56 // Perform Datapath power optimization 57 //------------------------------------------------------------------------- 58 bool OpticalGraph::performPowerOpt(OpticalNode* node_, const WavelengthGroup& wavelengths_, unsigned int number_detectors_, double util_) 59 { 60 // Total number of iterations 61 unsigned int number_iterations = 1250; 62 // Maximum IL + ER 63 double IL_ER_max = 10; 64 // Figure out the step size used in the sweep 65 double step = (double) (IL_ER_max / sqrt(2 * number_iterations)); 66 67 // Assume it is possible 68 bool possible = true; 69 70 // Begin optical data path power optimization 71 Log::printLine(getInstanceName() + " -> Beginning optical data path power optimization"); 72 73 // Trace the specified wavelengths 74 OpticalWavelength* wavelength = traceWavelength(wavelengths_, node_); 75 76 // For each data path found in the wavelength 77 const vector<OpticalDataPath>* data_paths = wavelength->getDataPaths(); 78 for (unsigned int i = 0; i < data_paths->size(); ++i) 79 { 80 const OpticalDataPath& data_path = data_paths->at(i); 81 // Default to worst possible modulator 82 double best_power = 1e99; 83 double best_IL = IL_ER_max - step; 84 double best_ER = step; 85 86 // Perform power optimization for this data path 87 Log::printLine(getInstanceName() + " -> Optimize data path - Laser = " + data_path.laser->getInstanceName() 88 + ", Modulator = " + data_path.modulator->getInstanceName()); 89 90 if (data_path.modulator->canOptimizeLoss()) 91 { 92 // Iterate over IL and ER to find optimal set of IL and ER 93 for (double IL = step; IL < IL_ER_max; IL += step) 94 { 95 for (double ER = step; ER <= (IL_ER_max - IL); ER += step) 96 { 97 // Ask the modulator to try this new ER and IL 98 bool success = data_path.modulator->setModulatorSpec(IL, ER); 99 // If the modulator was successful 100 if (success) 101 { 102 double laser_power = wavelength->getLaserPower(number_detectors_); 103 double modulator_power = data_path.modulator->getPower(util_); 104 double total_power = laser_power + modulator_power; 105 // If this is the new lowest power point 106 if (total_power < best_power) 107 { 108 best_power = total_power; 109 best_IL = IL; 110 best_ER = ER; 111 } 112 } 113 } 114 } 115 116 // Set IL and ER to the best ones we found 117 bool success = data_path.modulator->setModulatorSpec(best_IL, best_ER); 118 // If the best one we found was still not possible... 119 possible = possible && success; 120 121 // Print best IL and ER 122 Log::printLine(getInstanceName() + " -> Best IL=" + (String) best_IL + ", Best ER=" + (String) best_ER + 123 ", Best Laser/Mod Power=" + (String) best_power); 124 } 125 else 126 { 127 // Perform power optimization for this data path 128 Log::printLine(getInstanceName() + " -> Data path not set to allow optimization"); 129 } 130 } 131 132 // End optical data path power optimization 133 Log::printLine(getInstanceName() + " -> End optical data path power optimization"); 134 135 delete wavelength; 136 return possible; 137 } 138 139 140 //------------------------------------------------------------------------- 141 // Trace wavelength(s), returning a wavelength data structure 142 //------------------------------------------------------------------------- 143 OpticalWavelength* OpticalGraph::traceWavelength(const WavelengthGroup& wavelengths_, OpticalNode* node_) 144 { 145 setTreeNum(getTreeNum() + 1); 146 OpticalWavelength* wavelength = new OpticalWavelength("TraceWavelength", wavelengths_); 147 return traceWavelength(wavelength, node_, NULL, NULL, 0.0); 148 } 149 150 OpticalWavelength* OpticalGraph::traceWavelength(OpticalWavelength* wavelength_, OpticalNode* node_, OpticalLaser* laser_, OpticalModulator* modulator_, double loss_) 151 { 152 // If the node has already been visited, don't do anything! 153 if (node_->getVisitedNum() != getTreeNum()) 154 { 155 // Set the new parity for this node 156 node_->setVisitedNum(getTreeNum()); 157 158 // Calculate the loss of the current path 159 double current_loss = loss_ + node_->getLoss(); 160 // Check if the current node is a laser, modulator or detector 161 if(node_->getType() == OpticalNode::LASER) 162 { 163 // Set the laser lighting up the wavelength 164 ASSERT(laser_ == NULL, "[Error] " + getInstanceName() + " -> Multiple " + 165 "Lasers lighting up the wavelength!"); 166 laser_ = (OpticalLaser*) node_; 167 } 168 else if (node_->getType() == OpticalNode::MODULATOR) 169 { 170 // Check that the path already lit up by a laser and there are no 171 // modulators already driving data 172 ASSERT(laser_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " + 173 "modulator (" + node_->getInstanceName() + ") prior to being lit up by a laser!"); 174 ASSERT(modulator_ == NULL, "[Error] " + getInstanceName() + " -> Two modulators are driving" + 175 " the same optical data path (" + node_->getInstanceName() + ")!"); 176 modulator_ = (OpticalModulator*) node_; 177 } 178 else if (node_->getType() == OpticalNode::DETECTOR) 179 { 180 // Check that the path is both lit up by a laser and there is 181 // a modulator driving data 182 ASSERT(laser_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " + 183 "detector (" + node_->getInstanceName() + ") prior to being lit up by a laser!"); 184 ASSERT(modulator_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " + 185 "detector (" + node_->getInstanceName() + ") prior to being driven by a modulator!"); 186 // Add a detector to the wavelength 187 wavelength_->addDataPath(laser_, modulator_, (OpticalDetector*) node_, current_loss); 188 } 189 190 // Traverse downstream nodes to calculate the delay through each downstream path 191 vector<OpticalNode*>* d_nodes = node_->getDownstreamNodes(); 192 bool trace_downstream = (node_->getType() != OpticalNode::DETECTOR); 193 // Do special things when traversing filters 194 if (node_->getType() == OpticalNode::FILTER) 195 { 196 OpticalFilter* filter_node = (OpticalFilter*) node_; 197 if (filter_node->isDropped(wavelength_->getWavelengths())) 198 traceWavelength(wavelength_, filter_node->getDropPort(), laser_, modulator_, loss_ + filter_node->getDropLoss()); 199 200 // If the filter is not modeled as a complete drop, continue tracing downstream 201 trace_downstream = !filter_node->getDropAll(); 202 } 203 204 if (trace_downstream) 205 { 206 // Trace downstream nodes 207 for (unsigned int i = 0; i < d_nodes->size(); ++i) 208 traceWavelength(wavelength_, d_nodes->at(i), laser_, modulator_, current_loss); 209 } 210 } 211 return wavelength_; 212 } 213 214 //------------------------------------------------------------------------- 215 OpticalGraph::OpticalGraph(const OpticalGraph& /* graph_ */) 216 { 217 // Disabled 218 } 219 220 OpticalModel* OpticalGraph::getModel() 221 { 222 return m_model_; 223 } 224 225 void OpticalGraph::setTreeNum(int tree_num_) 226 { 227 msTreeNum = tree_num_; 228 return; 229 } 230 231 int OpticalGraph::getTreeNum() 232 { 233 return msTreeNum; 234 } 235 236} // namespace DSENT 237 238