summaryrefslogtreecommitdiff
path: root/ext/dsent/model/optical_graph/OpticalGraph.cc
blob: 424f2bcb278214be003e3faae4661dcee080c6a8 (plain)
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216

#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