/* 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* 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* 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