|  | /* Copyright (c) 2012 Massachusetts Institute of Technology | 
|  | * | 
|  | * Permission is hereby granted, free of charge, to any person obtaining a copy | 
|  | * of this software and associated documentation files (the "Software"), to deal | 
|  | * in the Software without restriction, including without limitation the rights | 
|  | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
|  | * copies of the Software, and to permit persons to whom the Software is | 
|  | * furnished to do so, subject to the following conditions: | 
|  | * | 
|  | * The above copyright notice and this permission notice shall be included in | 
|  | * all copies or substantial portions of the Software. | 
|  | * | 
|  | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
|  | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
|  | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 
|  | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
|  | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
|  | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
|  | * THE SOFTWARE. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include "model/optical_graph/OpticalGraph.h" | 
|  |  | 
|  | #include "model/OpticalModel.h" | 
|  | #include "model/optical_graph/OpticalNode.h" | 
|  | #include "model/optical_graph/OpticalLaser.h" | 
|  | #include "model/optical_graph/OpticalModulator.h" | 
|  | #include "model/optical_graph/OpticalFilter.h" | 
|  | #include "model/optical_graph/OpticalDetector.h" | 
|  | #include "model/optical_graph/OpticalWavelength.h" | 
|  |  | 
|  | namespace DSENT | 
|  | { | 
|  | // Initialize the next visited number to be one above the initial number | 
|  | // used by OpticalNode | 
|  | int OpticalGraph::msTreeNum = OpticalNode::OPTICAL_NODE_INIT_VISITED_NUM + 1; | 
|  |  | 
|  | OpticalGraph::OpticalGraph(const String& instance_name_, OpticalModel* model_) | 
|  | : m_instance_name_(instance_name_), m_model_(model_) | 
|  | { | 
|  |  | 
|  | } | 
|  |  | 
|  | OpticalGraph::~OpticalGraph() | 
|  | { | 
|  |  | 
|  | } | 
|  |  | 
|  | const String& OpticalGraph::getInstanceName() const | 
|  | { | 
|  | return m_instance_name_; | 
|  | } | 
|  |  | 
|  | //------------------------------------------------------------------------- | 
|  | // Perform Datapath power optimization | 
|  | //------------------------------------------------------------------------- | 
|  | bool OpticalGraph::performPowerOpt(OpticalNode* node_, const WavelengthGroup& wavelengths_, unsigned int number_detectors_, double util_) | 
|  | { | 
|  | // Total number of iterations | 
|  | unsigned int number_iterations = 1250; | 
|  | // Maximum IL + ER | 
|  | double IL_ER_max = 10; | 
|  | // Figure out the step size used in the sweep | 
|  | double step = (double) (IL_ER_max / sqrt(2 * number_iterations)); | 
|  |  | 
|  | // Assume it is possible | 
|  | bool possible = true; | 
|  |  | 
|  | // Begin optical data path power optimization | 
|  | Log::printLine(getInstanceName() + " -> Beginning optical data path power optimization"); | 
|  |  | 
|  | // Trace the specified wavelengths | 
|  | OpticalWavelength* wavelength = traceWavelength(wavelengths_, node_); | 
|  |  | 
|  | // For each data path found in the wavelength | 
|  | const vector<OpticalDataPath>* data_paths = wavelength->getDataPaths(); | 
|  | for (unsigned int i = 0; i < data_paths->size(); ++i) | 
|  | { | 
|  | const OpticalDataPath& data_path = data_paths->at(i); | 
|  | // Default to worst possible modulator | 
|  | double best_power = 1e99; | 
|  | double best_IL = IL_ER_max - step; | 
|  | double best_ER = step; | 
|  |  | 
|  | // Perform power optimization for this data path | 
|  | Log::printLine(getInstanceName() + " -> Optimize data path - Laser = " + data_path.laser->getInstanceName() | 
|  | + ", Modulator = " + data_path.modulator->getInstanceName()); | 
|  |  | 
|  | if (data_path.modulator->canOptimizeLoss()) | 
|  | { | 
|  | // Iterate over IL and ER to find optimal set of IL and ER | 
|  | for (double IL = step; IL < IL_ER_max; IL += step) | 
|  | { | 
|  | for (double ER = step; ER <= (IL_ER_max - IL); ER += step) | 
|  | { | 
|  | // Ask the modulator to try this new ER and IL | 
|  | bool success = data_path.modulator->setModulatorSpec(IL, ER); | 
|  | // If the modulator was successful | 
|  | if (success) | 
|  | { | 
|  | double laser_power = wavelength->getLaserPower(number_detectors_); | 
|  | double modulator_power = data_path.modulator->getPower(util_); | 
|  | double total_power = laser_power + modulator_power; | 
|  | // If this is the new lowest power point | 
|  | if (total_power < best_power) | 
|  | { | 
|  | best_power = total_power; | 
|  | best_IL = IL; | 
|  | best_ER = ER; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Set IL and ER to the best ones we found | 
|  | bool success = data_path.modulator->setModulatorSpec(best_IL, best_ER); | 
|  | // If the best one we found was still not possible... | 
|  | possible = possible && success; | 
|  |  | 
|  | // Print best IL and ER | 
|  | Log::printLine(getInstanceName() + " -> Best IL=" + (String) best_IL + ", Best ER=" + (String) best_ER + | 
|  | ", Best Laser/Mod Power=" + (String) best_power); | 
|  | } | 
|  | else | 
|  | { | 
|  | // Perform power optimization for this data path | 
|  | Log::printLine(getInstanceName() + " -> Data path not set to allow optimization"); | 
|  | } | 
|  | } | 
|  |  | 
|  | // End optical data path power optimization | 
|  | Log::printLine(getInstanceName() + " -> End optical data path power optimization"); | 
|  |  | 
|  | delete wavelength; | 
|  | return possible; | 
|  | } | 
|  |  | 
|  |  | 
|  | //------------------------------------------------------------------------- | 
|  | // Trace wavelength(s), returning a wavelength data structure | 
|  | //------------------------------------------------------------------------- | 
|  | OpticalWavelength* OpticalGraph::traceWavelength(const WavelengthGroup& wavelengths_, OpticalNode* node_) | 
|  | { | 
|  | setTreeNum(getTreeNum() + 1); | 
|  | OpticalWavelength* wavelength = new OpticalWavelength("TraceWavelength", wavelengths_); | 
|  | return traceWavelength(wavelength, node_, NULL, NULL, 0.0); | 
|  | } | 
|  |  | 
|  | OpticalWavelength* OpticalGraph::traceWavelength(OpticalWavelength* wavelength_, OpticalNode* node_, OpticalLaser* laser_, OpticalModulator* modulator_, double loss_) | 
|  | { | 
|  | // If the node has already been visited, don't do anything! | 
|  | if (node_->getVisitedNum() != getTreeNum()) | 
|  | { | 
|  | // Set the new parity for this node | 
|  | node_->setVisitedNum(getTreeNum()); | 
|  |  | 
|  | // Calculate the loss of the current path | 
|  | double current_loss = loss_ + node_->getLoss(); | 
|  | // Check if the current node is a laser, modulator or detector | 
|  | if(node_->getType() == OpticalNode::LASER) | 
|  | { | 
|  | // Set the laser lighting up the wavelength | 
|  | ASSERT(laser_ == NULL, "[Error] " + getInstanceName() + " -> Multiple " + | 
|  | "Lasers lighting up the wavelength!"); | 
|  | laser_ = (OpticalLaser*) node_; | 
|  | } | 
|  | else if (node_->getType() == OpticalNode::MODULATOR) | 
|  | { | 
|  | // Check that the path already lit up by a laser and there are no | 
|  | // modulators already driving data | 
|  | ASSERT(laser_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " + | 
|  | "modulator (" + node_->getInstanceName() + ") prior to being lit up by a laser!"); | 
|  | ASSERT(modulator_ == NULL, "[Error] " + getInstanceName() + " -> Two modulators are driving" + | 
|  | " the same optical data path (" + node_->getInstanceName() + ")!"); | 
|  | modulator_ = (OpticalModulator*) node_; | 
|  | } | 
|  | else if (node_->getType() == OpticalNode::DETECTOR) | 
|  | { | 
|  | // Check that the path is both lit up by a laser and there is | 
|  | // a modulator driving data | 
|  | ASSERT(laser_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " + | 
|  | "detector (" + node_->getInstanceName() + ") prior to being lit up by a laser!"); | 
|  | ASSERT(modulator_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " + | 
|  | "detector (" + node_->getInstanceName() + ") prior to being driven by a modulator!"); | 
|  | // Add a detector to the wavelength | 
|  | wavelength_->addDataPath(laser_, modulator_, (OpticalDetector*) node_, current_loss); | 
|  | } | 
|  |  | 
|  | // Traverse downstream nodes to calculate the delay through each downstream path | 
|  | vector<OpticalNode*>* d_nodes = node_->getDownstreamNodes(); | 
|  | bool trace_downstream = (node_->getType() != OpticalNode::DETECTOR); | 
|  | // Do special things when traversing filters | 
|  | if (node_->getType() == OpticalNode::FILTER) | 
|  | { | 
|  | OpticalFilter* filter_node = (OpticalFilter*) node_; | 
|  | if (filter_node->isDropped(wavelength_->getWavelengths())) | 
|  | traceWavelength(wavelength_, filter_node->getDropPort(), laser_, modulator_, loss_ + filter_node->getDropLoss()); | 
|  |  | 
|  | // If the filter is not modeled as a complete drop, continue tracing downstream | 
|  | trace_downstream = !filter_node->getDropAll(); | 
|  | } | 
|  |  | 
|  | if (trace_downstream) | 
|  | { | 
|  | // Trace downstream nodes | 
|  | for (unsigned int i = 0; i < d_nodes->size(); ++i) | 
|  | traceWavelength(wavelength_, d_nodes->at(i), laser_, modulator_, current_loss); | 
|  | } | 
|  | } | 
|  | return wavelength_; | 
|  | } | 
|  |  | 
|  | //------------------------------------------------------------------------- | 
|  | OpticalGraph::OpticalGraph(const OpticalGraph& /* graph_ */) | 
|  | { | 
|  | // Disabled | 
|  | } | 
|  |  | 
|  | OpticalModel* OpticalGraph::getModel() | 
|  | { | 
|  | return m_model_; | 
|  | } | 
|  |  | 
|  | void OpticalGraph::setTreeNum(int tree_num_) | 
|  | { | 
|  | msTreeNum = tree_num_; | 
|  | return; | 
|  | } | 
|  |  | 
|  | int OpticalGraph::getTreeNum() | 
|  | { | 
|  | return msTreeNum; | 
|  | } | 
|  |  | 
|  | } // namespace DSENT | 
|  |  |