001package com.net2plan.examples.general.reports; 002 003import java.text.DecimalFormat; 004import java.util.Arrays; 005import java.util.HashMap; 006import java.util.Iterator; 007import java.util.LinkedHashMap; 008import java.util.LinkedList; 009import java.util.List; 010import java.util.Map; 011 012import org.apache.commons.collections15.ListUtils; 013import org.apache.commons.lang.ArrayUtils; 014 015import com.net2plan.interfaces.networkDesign.IReport; 016import com.net2plan.interfaces.networkDesign.Link; 017import com.net2plan.interfaces.networkDesign.Net2PlanException; 018import com.net2plan.interfaces.networkDesign.NetPlan; 019import com.net2plan.interfaces.networkDesign.Route; 020import com.net2plan.libraries.OpticalImpairmentUtils; 021import com.net2plan.utils.Constants.OrderingType; 022import com.net2plan.utils.DoubleUtils; 023import com.net2plan.utils.InputParameter; 024import com.net2plan.utils.Quadruple; 025import com.net2plan.utils.StringUtils; 026import com.net2plan.utils.Triple; 027 028/** 029 * <p> 030 * This report shows line engineering information for WDM links in a multilayer optical network. The impairment calculations are based on the Gaussian Noise Model developed by Politecnico di Torino and inspired in the procedures described in the 2009 031 * ITU-T WDM manual "Optical fibres, cabbles and systems". 032 * </p> 033 * <p> 034 * The report assumes that the WDM network follows the scheme: 035 * </p> 036 * <ul> 037 * <li>In the net2plan object, nodes are OADMs, links are fiber links, and routes are lightpaths: WDM channels optically switched at intermediate nodes.</li> 038 * <li>Nodes are connected by unidirectional fiber links. Fiber link distance is given by the link length. Other specifications are given by fibers_XXX input parameters, each one describing the parameter for the fiber types specified in fibers_types, 039 * in the same order and separated by spaces. The fiber can be split into spans if optical amplifers (EDFAs) and/or passive components (PCs) are placed along the fiber. These spans can be of different fiber types as long as they are described in a 040 * link attribute called "fiberTypes". Must be separated by spaces and, in case that there were more spans than elements of the attribute, the default type given in "fiber_default_type" would be used.</li> 041 * <li>Optical line amplifiers (EDFAs) can be located in none, one or more positions in the fiber link, separating them in different spans. EDFAs are supposed to operate in the automatic gain control mode. Thus, the gain is the same, whatever the 042 * number of input WDM channels. EDFA positions (as distance" in km from the link start to the EDFA location), EDFA gains (assumed in dB) and EDFA noise figures (in dB) are read from the "edfaPositions_km", "edfaGains_dB" and "edfaNoiseFigures_dB" 043 * attributes of the links. The format of all attributes are the same: a string of numbers separated by spaces. The <i>i</i>-th number corresponding to the position/gain of the <i>i</i>-th EDFA. If the attributes do not exist, it is assumed that no 044 * EDFAs are placed in this link. EDFA specifications are given by "edfa_XXX" parameters</li> 045 * <li>There are not Dispersion compensating modules (DCMs) in the topoology, since the Gaussian Noise Model is used.</li> 046 * <li>Passive components are described by the link attributes "pcPositions_km" and "pcLosses_dB". The <i>i</i>-th number corresponding to the position/loss of the <i>i</i>-th PC. If the attributes do not exist, it is assumed that no PCs are placed 047 * in this link. Other specifications for PC will be described in teh pc_XXX input parameters.</li> 048 * <li>Fiber links start and end in OADM modules, that permit adding, dropping and optically switch individual WDM channels. OADMs have a pre-amplifier (traversed by drop and express channels) and a boost amplifier (traversed by add and express 049 * channels). They are supposed to equalize the channel power at their outputs, to a fixed value (added and express channels will thus have the same power in the fibers). Also, OADMs attenuate appropriately the optical signal coming from the 050 * pre-amplifier, in the drop channels, so that they fall within the receiver sensitivity range. OADM noise figures for add, drop and express channels are given as input parameters. PMD values for add, drop and express channels are computed assumming 051 * that: (i) add channel traverse a multiplexer and the booster, (ii) drop channels travese the pre-amplifier and a demultiplexer, (iii) express channels traverse the two amplifiers. The required parameters are provided in oadm_XXX parameters.</li> 052 * <li>Each channel ends in a receiver, with specifications given by "tp_XXX" parameters.</li> 053 * </ul> 054 * <p> 055 * The basic checks performed are: 056 * </p> 057 * <ul> 058 * <li>For each link, signal power levels are within operating ranges at the oadm/edfas, both when the link has one single active channel, or when all the "gn_spec_nCh" are active</li> 059 * <li>For each route (lightpath), OSNR (Optical Signal to Noise Ration) is within the operating range at the receiver. A set of margins are considered to account to several not directly considered impairments.</li> 060 * <li>For each route (lightpath), PMD (Polarization mode dispersion) is within the operating range at the receiver</li> 061 * </ul> 062 * 063 * @net2plan.keywords WDM, Multilayer 064 * @author Pablo Pavon-Marino, Elena Martin-Seoane 065 * @version 1.3, November 2017 */ 066public class Report_WDM_lineEngineering_GNModel implements IReport 067{ 068 /* Constants */ 069 private final static double delta_f = 6.25E-3; /* GHz of the slots in the grid */ 070 private final static double infinityThreshold_dB = 300; /* starting value to consider the OSNR perfect */ 071 072 /* Input parameters */ 073 private NetPlan netPlan; 074 private Map<String, String> reportParameters; 075 076 /* GN General parameters */ 077 private final InputParameter gn_gen_f0_THz = new InputParameter("gn_gen_f0_THz", (double) 192.075, "Starting frequency of the laser grid used to describe the WDM system [THz]"); 078 private final InputParameter gn_gen_ns = new InputParameter("gn_gen_ns", (int) 800, "Number of 6.25 GHz slots in the grid"); 079 080 /* Usable wavelengths */ 081 private double channels_minChannelLambda_nm; 082 private double channels_maxChannelLambda_nm; 083 084 /* GN spectrum description */ 085 private final InputParameter gn_spec_nCh = new InputParameter("gn_spec_nCh", (int) 16, "Number of used channels defined in the spectrum."); 086 private final InputParameter gn_spec_laserPosition = new InputParameter("gn_spec_laserPosition", "false false true false false false", "A list of booleans indicating whether a laser is turned on or not (per each channel)"); 087 private final InputParameter gn_spec_bandwidthCh_THz = new InputParameter("gn_spec_bandwidthCh_THz", (double) 0.032, "The -3 dB WDM channel bandwidth (for a root raised cosine, it is equal to the symbol rate)"); 088 089 /* Fiber specifications */ 090 private final InputParameter fiber_PMD_ps_per_sqroot_km = new InputParameter("fiber_PMD_ps_per_sqroot_km", (double) 0.4, "Polarization mode dispersion per km^0.5 of fiber (PMD_Q link factor)"); 091 private final InputParameter fiber_default_type = new InputParameter("fiber_default_type", "SMF", 092 "A string calling the type of fiber described (can be override by the 'fiberTypes' Net2Plan attribute). Must be a value from 'fibers_types'."); 093 /* GN Fiber parameters */ 094 private final InputParameter fibers_alpha_dB_per_km = new InputParameter("fibers_alpha_dB_per_km", "0.2 0.22", "The attenuation coefficient for each fiber type [dB/km]"); 095 private final InputParameter fibers_alpha1st_dB_per_km_per_THz = new InputParameter("fibers_alpha1st_dB_per_km_per_THz", "0 0", 096 "The first derivative of alpha indicating the alpha slope for each fiber type [dB/km/THz]. Should be zero if you assume a flat attenuation with respect to the frequency"); 097 private final InputParameter fibers_beta2_ps2_per_km = new InputParameter("fibers_beta2_ps2_per_km", "21.27 21", "The dispersion coefficient for each fiber type [ps^2/km]"); 098 private final InputParameter fibers_n2_m2_per_W = new InputParameter("fibers_n2_m2_per_W", "2.5E-20 2.5E-20", "Second-order nonlinear refractive index for each fiber type [m^2/W]. A typical value is 2.5E-20 m^2/W"); 099 private final InputParameter fibers_Aeff_um2 = new InputParameter("fibers_Aeff_um2", "77.77 70", "The effective area for each fiber type [um^2]"); 100 private final InputParameter fibers_types = new InputParameter("fibers_types", "SMF NZDF", "The names of the fiber types described in the other fibers_XXX parameters. They MUST BE ordered."); 101 private final InputParameter fibers_numberOfFiberTypes = new InputParameter("fibers_numberOfFiberTypes", (int) 2, "The number of different fiber types described. Must be equal to the length of the others fibers_XXX parameters."); 102 103 /* Transponder specifications */ 104 private final InputParameter tp_minOSNR_dB = new InputParameter("tp_minOSNR_dB", (double) 7, "Minimum OSNR needed at the receiver"); 105 private final InputParameter tp_minWavelength_nm = new InputParameter("tp_minWavelength_nm", (double) 1529.55, "Minimum wavelength usable by the transponder"); 106 private final InputParameter tp_maxWavelength_nm = new InputParameter("tp_maxWavelength_nm", (double) 1561.84, "Maximum wavelength usable by the transponder"); 107 private final InputParameter tp_pmdTolerance_ps = new InputParameter("tp_pmdTolerance_ps", (double) 10, "Maximum tolarance of polarizarion mode dispersion (mean of differential group delay) in ps at the receiver"); 108 private final InputParameter tp_inputPowerSensitivityMin_dBm = new InputParameter("tp_inputPowerSensitivityMin_dBm", (double) -20, "Minimum input power at the receiver in dBm"); 109 private final InputParameter tp_inputPowerSensitivityMax_dBm = new InputParameter("tp_inputPowerSensitivityMax_dBm", (double) -8, "Maximum input power at the receiver in dBm"); 110 111 /* OADM specs */ 112 private final InputParameter oadm_outputPowerPerChannel_W = new InputParameter("oadm_outputPowerPerChannel_W", (double) 1E-3, "The WDM channel power at the output of the OADM [W]"); 113 private final InputParameter oadm_perChannelMinInputPower_dBm = new InputParameter("oadm_perChannelMinInputPower_dBm", (double) -19, "Minimum power needed at the OADM input"); 114 private final InputParameter oadm_perChannelMaxInputPower_dBm = new InputParameter("oadm_perChannelMaxInputPower_dBm", (double) 1000, "Maximum power admitted at the OADM input"); 115 private final InputParameter oadm_muxDemuxPMD_ps = new InputParameter("oadm_muxDemuxPMD_ps", (double) 0.5, "PMD of the mux/demux inside the OADMs. Does not affect express lightpaths"); 116 private final InputParameter oadm_preAmplifierPMD_ps = new InputParameter("oadm_preAmplifierPMD_ps", (double) 0.5, "PMD off OADM preamplifier"); 117 private final InputParameter oadm_boosterPMD_ps = new InputParameter("oadm_boosterPMD_ps", (double) 0.5, "PMD off OADM booster amplifier"); 118 private final InputParameter oadm_addChannelNoiseFactor_dB = new InputParameter("oadm_addChannelNoiseFactor_dB", (double) 6, "Noise factor observed by add channels"); 119 private final InputParameter oadm_dropChannelNoiseFactor_dB = new InputParameter("oadm_dropChannelNoiseFactor_dB", (double) 6, "Noise factor observed by drop channels"); 120 private final InputParameter oadm_expressChannelNoiseFactor_dB = new InputParameter("oadm_expressChannelNoiseFactor_dB", (double) 10, "Noise factor observed by express channels"); 121 122 /* Optical line amplifier specifications */ 123 private final InputParameter edfa_minWavelength_nm = new InputParameter("edfa_minWavelength_nm", (double) 1530, "Minimum wavelength usable by the EDFA"); 124 private final InputParameter edfa_maxWavelength_nm = new InputParameter("edfa_maxWavelength_nm", (double) 1563, "Maximum wavelength usable by the EDFA"); 125 private final InputParameter edfa_minInputPower_dBm = new InputParameter("edfa_minInputPower_dBm", (double) -29, "Minimum input power at the EDFA"); 126 private final InputParameter edfa_maxInputPower_dBm = new InputParameter("edfa_maxInputPower_dBm", (double) 2, "Maximum input power at the EDFA"); 127 private final InputParameter edfa_minOutputPower_dBm = new InputParameter("edfa_minOutputPower_dBm", (double) -6, "Minimum output power at the EDFA"); 128 private final InputParameter edfa_maxOutputPower_dBm = new InputParameter("edfa_maxOutputPower_dBm", (double) 19, "Maximum output power at the EDFA"); 129 private final InputParameter edfa_minGain_dB = new InputParameter("edfa_minGain_dB", (double) 17, "Minimum gain at the EDFA"); 130 private final InputParameter edfa_maxGain_dB = new InputParameter("edfa_maxGain_dB", (double) 23, "Maximum gain at the EDFA"); 131 private final InputParameter edfa_PMD_ps = new InputParameter("edfa_PMD_ps", (double) 0.5, "Polarization mode dispersion in ps added by the EDFA"); 132 private final InputParameter edfa_default_noiseFactor_dB = new InputParameter("edfa_default_noiseFactor_dB", (double) 3, "Default noise factor used when the link does not have the attribute"); 133 private final InputParameter edfa_noiseFactorMaximumGain_dB = new InputParameter("edfa_noiseFactorMaximumGain_dB", (double) 5, 134 "Noise factor at the EDFA when the gain is in its upper limit (linear interpolation is used to estimate the noise figure at other gains)"); 135 private final InputParameter edfa_noiseFactorMinimumGain_dB = new InputParameter("edfa_noiseFactorMinimumGain_dB", (double) 5, 136 "Noise factor at the EDFA when the gain is in its lower limit (linear interpolation is used to estimate the noise figure at other gains)"); 137 138 /* PC specs */ 139 private final InputParameter pc_PMD_ps = new InputParameter("pc_PMD_ps", (double) 0.5, "Polarization mode dispersion in ps added by the PC"); 140 141 /* OSNR penalties */ 142 private final InputParameter osnrPenalty_nonLinear_dB = new InputParameter("osnrPenalty_nonLinear_dB", (double) 2, "OSNR penalty caused by the non-linear effects SPM, XPM, FWM and Brillouin / Raman scattering"); 143 private final InputParameter osnrPenalty_PMD_dB = new InputParameter("osnrPenalty_PMD_dB", (double) 0.5, "OSNR penalty caused by the polarization mode dispersion (assumed within limits)"); 144 private final InputParameter osnrPenalty_PDL_dB = new InputParameter("osnrPenalty_PDL_dB", (double) 0.3, "OSNR penalty caused by polarization dispersion losses"); 145 private final InputParameter osnrPenalty_transmitterChirp_dB = new InputParameter("osnrPenalty_transmitterChirp_dB", (double) 0.5, "OSNR penalty caused by transmitter chirp "); 146 private final InputParameter osnrPenalty_OADMCrosstalk_dB = new InputParameter("osnrPenalty_OADMCrosstalk_dB", (double) 0.8, "OSNR penalty caused by the crosstalk at the OADMs"); 147 private final InputParameter osnrPenalty_unassignedMargin_dB = new InputParameter("osnrPenalty_unassignedMargin_dB", (double) 3, "OSNR penalty caused by not assigned margins (e.g. random effects, aging, ...)"); 148 private double osnrPenalty_SUM_dB; 149 150 /* Global parameters */ 151 private Map<String, double[]> spectrumParameters; 152 Map<String, Map<String, Double>> fiberParameters; 153 private double centralFreq_THz; 154 private double[] frequenciesPerChannel_THz; 155 156 @Override 157 public String executeReport(NetPlan netPlan, Map<String, String> reportParameters, Map<String, String> net2planParameters) 158 { 159 /* Input parameters */ 160 this.netPlan = netPlan; 161 this.reportParameters = reportParameters; 162 163 /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */ 164 InputParameter.initializeAllInputParameterFieldsOfObject(this, reportParameters); 165 fiberParameters = getFiberSpecsMap(); 166 167 /* Initialize GN Parameters */ 168 centralFreq_THz = gn_gen_f0_THz.getDouble() + (Math.floor(gn_gen_ns.getInt() / 2.0) * delta_f); 169 final Boolean[] laser_position = getLaserPositions(StringUtils.toBooleanArray(StringUtils.split(gn_spec_laserPosition.getString()))); 170 frequenciesPerChannel_THz = getBasebandFrequency(laser_position); 171 172 /* Usable wavelengths */ 173 channels_minChannelLambda_nm = OpticalImpairmentUtils.constant_c / ((gn_gen_f0_THz.getDouble() * 1e3) + gn_gen_ns.getInt() * delta_f); 174 channels_maxChannelLambda_nm = (OpticalImpairmentUtils.constant_c / (gn_gen_f0_THz.getDouble() * 1e12)) * 1e9; 175 176 /* OSNR penalties */ 177 osnrPenalty_SUM_dB = osnrPenalty_nonLinear_dB.getDouble() + osnrPenalty_PMD_dB.getDouble() + osnrPenalty_PDL_dB.getDouble() + osnrPenalty_transmitterChirp_dB.getDouble() + osnrPenalty_OADMCrosstalk_dB.getDouble() 178 + osnrPenalty_unassignedMargin_dB.getDouble(); 179 180 final Map<Link, List<Quadruple<Double, String, Double, String>>> elements_e = new LinkedHashMap<Link, List<Quadruple<Double, String, Double, String>>>(); 181 final Map<Link, List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>>> impairments_e = new LinkedHashMap<Link, List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>>>(); 182 final Map<Link, List<String>> warnings_e = new LinkedHashMap<Link, List<String>>(); 183 184 for (Link link : netPlan.getLinks()) 185 { 186 final List<Link> seqLinks = new LinkedList<Link>(); 187 seqLinks.add(link); 188 final List<Quadruple<Double, String, Double, String>> elementPositions = getElementPositionsListPerLightpath(seqLinks); 189 190 spectrumParameters = initializeSpectrum(); 191 192 final List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>> impairmentsAtInputAndOutputs = OpticalImpairmentUtils.computeImpairments(elementPositions, spectrumParameters, fiberParameters, 193 oadm_outputPowerPerChannel_W.getDouble(), fiber_PMD_ps_per_sqroot_km.getDouble(), edfa_PMD_ps.getDouble(), pc_PMD_ps.getDouble(), oadm_muxDemuxPMD_ps.getDouble(), oadm_preAmplifierPMD_ps.getDouble(), 194 oadm_boosterPMD_ps.getDouble(), frequenciesPerChannel_THz, centralFreq_THz, tp_inputPowerSensitivityMin_dBm.getDouble(), tp_inputPowerSensitivityMax_dBm.getDouble()); 195 final List<String> warningMessages = computeWarningMessages(elementPositions, impairmentsAtInputAndOutputs); 196 197 elements_e.put(link, elementPositions); 198 impairments_e.put(link, impairmentsAtInputAndOutputs); 199 warnings_e.put(link, warningMessages); 200 } 201 202 final Map<Route, List<Quadruple<Double, String, Double, String>>> elements_r = new LinkedHashMap<Route, List<Quadruple<Double, String, Double, String>>>(); 203 final Map<Route, List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>>> impairments_r = new LinkedHashMap<Route, List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>>>(); 204 final Map<Route, List<String>> warnings_r = new LinkedHashMap<Route, List<String>>(); 205 for (Route r : netPlan.getRoutes()) 206 { 207 final List<Link> seqLinks = r.getSeqLinks(); 208 final List<Quadruple<Double, String, Double, String>> elementPositions = getElementPositionsListPerLightpath(seqLinks); 209 210 spectrumParameters = initializeSpectrum(); 211 212 final List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>> impairmentsAtInputAndOutputs = OpticalImpairmentUtils.computeImpairments(elementPositions, spectrumParameters, fiberParameters, 213 oadm_outputPowerPerChannel_W.getDouble(), fiber_PMD_ps_per_sqroot_km.getDouble(), edfa_PMD_ps.getDouble(), pc_PMD_ps.getDouble(), oadm_muxDemuxPMD_ps.getDouble(), oadm_preAmplifierPMD_ps.getDouble(), 214 oadm_boosterPMD_ps.getDouble(), frequenciesPerChannel_THz, centralFreq_THz, tp_inputPowerSensitivityMin_dBm.getDouble(), tp_inputPowerSensitivityMax_dBm.getDouble()); 215 final List<String> warningMessages = computeWarningMessages(elementPositions, impairmentsAtInputAndOutputs); 216 217 elements_r.put(r, elementPositions); 218 impairments_r.put(r, impairmentsAtInputAndOutputs); 219 warnings_r.put(r, warningMessages); 220 } 221 222 return printReport(elements_e, impairments_e, warnings_e, elements_r, impairments_r, warnings_r); 223 } 224 225 @Override 226 public String getDescription() 227 { 228 return "This report shows line engineering information for WDM links in the network. " + " The report assumes that the WDM network follows the scheme:\n" 229 + " * In the net2plan object, nodes are OADMs, links are fiber links and routes are lightpaths:\n" + "WDM channels optically switched at intermediate nodes.\n" 230 + " * Nodes are connected by unidirectional fiber links. Fiber link distance is" + " given by the link length. Other specifications are given by fibers_XXX input parameters, each one describing the" 231 + "parameter for the fiber types specified in fibers_types, in the same order and separated by" + "spaces. The fiber can be split into spans if optical amplifers (EDFAs) and/or passive components" 232 + "(PCs) are placed along the fiber. These spans can be of different fiber types as long as they are" + "described in a link attribute called \"fiberTypes\". Must be separated by spaces and, in case that" 233 + "there were more spans than elements of the attribute, the default type given in" + "\"fiber_default_type\" would be used." + " * Optical line amplifiers (EDFAs) can be located in none, one or more" 234 + " positions in the fiber link, separating them into different spans. EDFAs are" + " supposed to operate in the automatic gain control mode. Thus, the gain is the" 235 + " same, whatever the number of input WDM channels. EDFA positions (as distance" + " in km from the link start to the EDFA location), EDFA gains (assumed in" 236 + " dB) and EDFA noise figures (in dB) are read from the \"edfaPositions_km\", \"edfaGains_dB\" and \"edfaNoiseFigures_dB\"" + " attributes of the links. The format of all attributes will be the same: a string of numbers" 237 + " separated by spaces. The i-th number corresponding to the position/gain of the" + " i-th EDFA. If the attributes do not exist, it is assumed that no EDFAs" 238 + " are placed in this link. EDFA specifications are given by \"edfa_XXX\" parameters.\n" + " * Passive components are described by the link attributes \"pcPositions_km\" and \"pcLosses_dB\".\n" 239 + " The i-th number corresponding to the position/loss of the i-th PC.\n" + " If the attributes do not exist, it is assumed that no PCs are placed in this link. \n" + " Further description in the HTML generated."; 240 } 241 242 @Override 243 public List<Triple<String, String, String>> getParameters() 244 { 245 /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */ 246 return InputParameter.getInformationAllInputParameterFieldsOfObject(this); 247 } 248 249 @Override 250 public String getTitle() 251 { 252 return "WDM line engineering with GN calculations"; 253 } 254 255 /** Checks if the number of elements in the fiber input parameters is always the same. If it is, returns a Map for each type of fiber with its parameters 256 * 257 * @return Map("FiberTypeName", Map("param", value)) */ 258 private Map<String, Map<String, Double>> getFiberSpecsMap() 259 { 260 final Map<String, Map<String, Double>> fiberSpecs = new HashMap<String, Map<String, Double>>(); 261 262 final String[] fiberTypes = StringUtils.split(fibers_types.getString()); 263 final double[] fiberAlphas = StringUtils.toDoubleArray(StringUtils.split(fibers_alpha_dB_per_km.getString())); 264 final double[] fiberAlpha1sts = StringUtils.toDoubleArray(StringUtils.split(fibers_alpha1st_dB_per_km_per_THz.getString())); 265 final double[] fiberBeta2s = StringUtils.toDoubleArray(StringUtils.split(fibers_beta2_ps2_per_km.getString())); 266 final double[] fiberAeffs = StringUtils.toDoubleArray(StringUtils.split(fibers_Aeff_um2.getString())); 267 final double[] fiberN2s = StringUtils.toDoubleArray(StringUtils.split(fibers_n2_m2_per_W.getString())); 268 final int numFiberTypes = fibers_numberOfFiberTypes.getInt(); 269 270 if (numFiberTypes != fiberTypes.length || numFiberTypes != fiberAlphas.length || numFiberTypes != fiberAlpha1sts.length || numFiberTypes != fiberBeta2s.length || numFiberTypes != fiberAeffs.length || numFiberTypes != fiberN2s.length) 271 throw new Net2PlanException("Incorrect number of fiber parameters."); 272 273 boolean containsDefaultType = false; 274 for (String string : fiberTypes) 275 if (string.equalsIgnoreCase(fiber_default_type.getString())) 276 containsDefaultType = true; 277 278 if (!containsDefaultType) 279 throw new Net2PlanException("fiber_default_type is not contained in the fibers_types list."); 280 281 for (int i = 0; i < fiberTypes.length; i++) 282 { 283 final String fiberType = fiberTypes[i]; 284 285 final Map<String, Double> specs_thisType = new HashMap<String, Double>(); 286 specs_thisType.put(OpticalImpairmentUtils.stFiber_alpha_dB_per_km, fiberAlphas[i]); 287 specs_thisType.put(OpticalImpairmentUtils.stFiber_alpha1st_dB_per_km_per_THz, fiberAlpha1sts[i]); 288 specs_thisType.put(OpticalImpairmentUtils.stFiber_beta2_ps2_per_km, fiberBeta2s[i]); 289 specs_thisType.put(OpticalImpairmentUtils.stFiber_effectiveArea_um2, fiberAeffs[i]); 290 specs_thisType.put(OpticalImpairmentUtils.stFiber_n2Coeff_m2_per_W, fiberN2s[i]); 291 292 fiberSpecs.put(fiberType, specs_thisType); 293 } 294 295 return fiberSpecs; 296 } 297 298 /** Initializes all spectrum parameters with the given input parameters 299 * 300 * @return initial spectrum */ 301 private Map<String, double[]> initializeSpectrum() 302 { 303 final Map<String, double[]> spectrumParameters = new HashMap<>(); 304 final int numChannels = gn_spec_nCh.getInt(); 305 306 final double[] bandwidthPerChannel_THz = new double[numChannels]; 307 final double[] powerPerChannel_W = new double[numChannels]; 308 final double[] aseNoisePower_W = new double[numChannels]; 309 final double[] nliNoisePower_W = new double[numChannels]; 310 311 Arrays.fill(bandwidthPerChannel_THz, gn_spec_bandwidthCh_THz.getDouble()); 312 Arrays.fill(powerPerChannel_W, oadm_outputPowerPerChannel_W.getDouble()); 313 Arrays.fill(aseNoisePower_W, 0); 314 Arrays.fill(nliNoisePower_W, 0); 315 316 spectrumParameters.put(OpticalImpairmentUtils.stSpectrum_bandwidthPerChannel_THz, bandwidthPerChannel_THz); 317 spectrumParameters.put(OpticalImpairmentUtils.stSpectrum_powerPerChannel_W, powerPerChannel_W); 318 spectrumParameters.put(OpticalImpairmentUtils.stSpectrum_aseNoisePower_W, aseNoisePower_W); 319 spectrumParameters.put(OpticalImpairmentUtils.stSpectrum_nliNoisePowerg_W, nliNoisePower_W); 320 321 return spectrumParameters; 322 } 323 324 /** Gets an array of booleans with the status of the lasers for all channels 325 * 326 * @param lp laser positions per channel 327 * @return extended array with the lp of every channel */ 328 private Boolean[] getLaserPositions(boolean[] lp) 329 { 330 331 List<Boolean> lasers = new LinkedList<>(); 332 final List<Boolean> lps = Arrays.asList(ArrayUtils.toObject(lp)); 333 334 for (int i = 0; i < gn_spec_nCh.getInt(); i++) 335 lasers = ListUtils.union(lasers, lps); 336 337 return lasers.toArray(new Boolean[lasers.size()]); 338 339 } 340 341 /** Initializes frequencies for each channel 342 * 343 * @param laser_position boolean whether a laser is turn on or not 344 * @return frequencies per channel */ 345 private double[] getBasebandFrequency(Boolean[] laser_position) 346 { 347 double[] frequenciesPerChannel_THz = DoubleUtils.zeros(gn_spec_nCh.getInt()); 348 349 int count = 0; 350 for (int i = 0; i < laser_position.length; i++) 351 if (laser_position[i]) 352 frequenciesPerChannel_THz[count++] = (gn_gen_f0_THz.getDouble() - centralFreq_THz) + delta_f * i; 353 354 return frequenciesPerChannel_THz; 355 } 356 357 /** Gets the network warnings for the elements and impairments given 358 * 359 * @param elementPositions List of Quadruple of(position [km], type, 3rd: data; 4th: auxData) 360 * @param impairmentsAtInputAndOutputs List of Quadruple of (before element Map(paramName, value), before element PMD, after element Map(paramName, value), after element PMD) 361 * @return warnings */ 362 private List<String> computeWarningMessages(List<Quadruple<Double, String, Double, String>> elementPositions, List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>> impairmentsAtInputAndOutputs) 363 { 364 final double numChannels_dB = OpticalImpairmentUtils.linear2dB(gn_spec_nCh.getInt()); 365 final int centralChannel = Math.floorDiv(gn_spec_nCh.getInt(), 2); 366 final List<String> res = new LinkedList<String>(); 367 368 final Iterator<Quadruple<Double, String, Double, String>> it_elementPositions = elementPositions.iterator(); 369 final Iterator<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>> it_impairments = impairmentsAtInputAndOutputs.iterator(); 370 371 while (it_elementPositions.hasNext()) 372 { 373 String st = ""; 374 375 final Quadruple<Double, String, Double, String> thisElement = it_elementPositions.next(); 376 final Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double> thisImpairments = it_impairments.next(); 377 378 final double initialPosition_km = thisElement.getFirst(); 379 final String name = thisElement.getSecond(); 380 final double elementData = thisElement.getThird(); 381 382 final Map<String, double[]> preImpSpectrum = thisImpairments.getFirst(); 383 final double pre_powerPerChannel_dBm = OpticalImpairmentUtils.linear2dB(preImpSpectrum.get(OpticalImpairmentUtils.stSpectrum_powerPerChannel_W)[centralChannel] * 1e3); 384 385 final Map<String, double[]> postImpSpectrum = thisImpairments.getThird(); 386 final double post_powerPerChannel_dBm = OpticalImpairmentUtils.linear2dB(postImpSpectrum.get(OpticalImpairmentUtils.stSpectrum_powerPerChannel_W)[centralChannel] * 1e3); 387 388 if (name.equalsIgnoreCase("OADM-ADD")) 389 { 390 /* Wavelengths in use within transponder range */ 391 if (channels_minChannelLambda_nm < tp_minWavelength_nm.getDouble()) 392 st += "Wavelength " + channels_minChannelLambda_nm + " nm is outside the transponder range [" + tp_minWavelength_nm.getDouble() + " nm, " + tp_maxWavelength_nm.getDouble() + " nm]"; 393 if (channels_maxChannelLambda_nm > tp_maxWavelength_nm.getDouble()) 394 st += "Wavelength " + channels_maxChannelLambda_nm + " nm is outside the transponder range [" + tp_minWavelength_nm.getDouble() + " nm, " + tp_maxWavelength_nm.getDouble() + " nm]"; 395 396 /* Output power within limits */ 397 if (Math.abs(post_powerPerChannel_dBm - OpticalImpairmentUtils.linear2dB(oadm_outputPowerPerChannel_W.getDouble() * 1e3)) > 1E-3) 398 st += "At " + initialPosition_km + "km: Power at the OADM-ADD output is " + post_powerPerChannel_dBm + " dBm. It should be: " + OpticalImpairmentUtils.linear2dB(oadm_outputPowerPerChannel_W.getDouble() * 1e3); 399 400 } else if (name.equalsIgnoreCase("OADM-EXPRESS")) 401 { 402 /* Input power within limits */ 403 if (pre_powerPerChannel_dBm < oadm_perChannelMinInputPower_dBm.getDouble() - 1E-3) 404 st += "At " + initialPosition_km + "km: Power at the OADM-EXPRESS input is " + pre_powerPerChannel_dBm + " dBm. It should be between [" + oadm_perChannelMinInputPower_dBm.getDouble() + ", " 405 + oadm_perChannelMaxInputPower_dBm.getDouble() + "] dBm"; 406 if (pre_powerPerChannel_dBm > oadm_perChannelMaxInputPower_dBm.getDouble() + 1E-3) 407 st += "At " + initialPosition_km + "km: Power at the OADM-EXPRESS input is " + pre_powerPerChannel_dBm + " dBm. It should be between [" + oadm_perChannelMinInputPower_dBm.getDouble() + ", " 408 + oadm_perChannelMaxInputPower_dBm.getDouble() + "] dBm"; 409 410 /* Output power within limits */ 411 if (Math.abs(post_powerPerChannel_dBm - OpticalImpairmentUtils.linear2dB(oadm_outputPowerPerChannel_W.getDouble() * 1e3)) > 1E-3) 412 st += "At " + initialPosition_km + "km: Power at the OADM-EXPRESS output is " + post_powerPerChannel_dBm + " dBm. It should be: " + OpticalImpairmentUtils.linear2dB(oadm_outputPowerPerChannel_W.getDouble() * 1e3); 413 414 } else if (name.equalsIgnoreCase("OADM-DROP")) 415 { 416 final double post_PMDSquared_ps2 = thisImpairments.getFourth(); 417 final Triple<double[], double[], double[]> post_OSNR_linear = OpticalImpairmentUtils.getOSNR(postImpSpectrum); 418 419 /* Input power within limits */ 420 if (pre_powerPerChannel_dBm < oadm_perChannelMinInputPower_dBm.getDouble() - 1E-3) 421 st += "At " + initialPosition_km + "km: Power at the OADM-DROP input is " + pre_powerPerChannel_dBm + " dBm. It should be between [" + oadm_perChannelMinInputPower_dBm.getDouble() + "," 422 + oadm_perChannelMaxInputPower_dBm.getDouble() + "] dBm"; 423 if (pre_powerPerChannel_dBm > oadm_perChannelMaxInputPower_dBm.getDouble() + 1E-3) 424 st += "At " + initialPosition_km + "km: Power at the OADM-DROP input is " + pre_powerPerChannel_dBm + " dBm. It should be between [" + oadm_perChannelMinInputPower_dBm.getDouble() + "," 425 + oadm_perChannelMaxInputPower_dBm.getDouble() + "] dBm"; 426 427 /* Output power within limits */ 428 if (post_powerPerChannel_dBm < tp_inputPowerSensitivityMin_dBm.getDouble() - 1E-3) 429 st += "At " + initialPosition_km + "km: Power at the OADM-DROP output is " + post_powerPerChannel_dBm + ". It should be between [" + tp_inputPowerSensitivityMin_dBm.getDouble() + "," + tp_inputPowerSensitivityMax_dBm.getDouble() 430 + "] dBm"; 431 if (post_powerPerChannel_dBm > tp_inputPowerSensitivityMax_dBm.getDouble() + 1E-3) 432 st += "At " + initialPosition_km + "km: Power at the OADM-DROP output is " + post_powerPerChannel_dBm + ". It should be between [" + tp_inputPowerSensitivityMin_dBm.getDouble() + "," + tp_inputPowerSensitivityMax_dBm.getDouble() 433 + "] dBm"; 434 435 /* OSNR within limits */ 436 if (OpticalImpairmentUtils.linear2dB(post_OSNR_linear.getThird()[centralChannel]) < tp_minOSNR_dB.getDouble() + osnrPenalty_SUM_dB) 437 st += "At " + initialPosition_km + "km: OSNR at the RECEIVER is " + OpticalImpairmentUtils.linear2dB(post_OSNR_linear.getThird()[centralChannel]) + " dB. It is below the tolerance plus margin " + tp_minOSNR_dB.getDouble() 438 + " dB + penalties " + osnrPenalty_SUM_dB + " dB = " + (tp_minOSNR_dB.getDouble() + osnrPenalty_SUM_dB) + " dB)"; 439 440 /* PMD tolerance at the receiver */ 441 final double pmdAtReceiver = Math.sqrt(post_PMDSquared_ps2); 442 if (pmdAtReceiver > tp_pmdTolerance_ps.getDouble()) 443 st += "At " + initialPosition_km + "km: PMD at the RECEIVER is " + pmdAtReceiver + " ps. It is above the maximum PMD tolerance (" + tp_pmdTolerance_ps.getDouble() + " ps)"; 444 445 } else if (name.equalsIgnoreCase("SPAN")) 446 {} else if (name.equalsIgnoreCase("EDFA")) 447 { 448 final double edfaGain_dB = elementData; 449 450 /* Wavelengths within limits */ 451 if (channels_minChannelLambda_nm < edfa_minWavelength_nm.getDouble()) 452 st += "Wavelength " + channels_minChannelLambda_nm + " nm is outside the transponder range [" + edfa_minWavelength_nm.getDouble() + " nm, " + edfa_maxWavelength_nm.getDouble() + " nm]"; 453 if (channels_maxChannelLambda_nm > edfa_maxWavelength_nm.getDouble()) 454 st += "Wavelength " + channels_maxChannelLambda_nm + " nm is outside the transponder range [" + edfa_minWavelength_nm.getDouble() + " nm, " + edfa_maxWavelength_nm.getDouble() + " nm]"; 455 456 /* Gain within limits */ 457 if (edfaGain_dB < edfa_minGain_dB.getDouble() - 1E-3) 458 st += "At " + initialPosition_km + "km: EDFA gain is " + edfaGain_dB + " dB. It should be between [" + edfa_minGain_dB.getDouble() + ", " + edfa_maxGain_dB.getDouble() + "] dB"; 459 if (edfaGain_dB > edfa_maxGain_dB.getDouble() + 1E-3) 460 st += "At " + initialPosition_km + "km: EDFA gain is " + edfaGain_dB + " dB. It should be between [" + edfa_minGain_dB.getDouble() + ", " + edfa_maxGain_dB.getDouble() + "] dB"; 461 462 /* Input power within limits */ 463 if (pre_powerPerChannel_dBm < edfa_minInputPower_dBm.getDouble() - 1E-3) 464 st += "At " + initialPosition_km + "km: Power at the EDFA input is (is one WDM channel) " + pre_powerPerChannel_dBm + " dBm. It should be between [" + edfa_minInputPower_dBm.getDouble() + ", " + edfa_maxInputPower_dBm.getDouble() 465 + "] dBm"; 466 if (pre_powerPerChannel_dBm + numChannels_dB > edfa_maxInputPower_dBm.getDouble() + 1E-3) 467 st += "At " + initialPosition_km + "km: Power at the EDFA input is (if all WDM channels were active) " + (pre_powerPerChannel_dBm + numChannels_dB) + " dBm. It should be between [" + edfa_minInputPower_dBm.getDouble() + "," 468 + edfa_maxInputPower_dBm.getDouble() + "] dBm"; 469 470 /* Output power within limits */ 471 if (post_powerPerChannel_dBm < edfa_minOutputPower_dBm.getDouble() - 1E-3) 472 st += "At " + initialPosition_km + "km: Power at the EDFA output is (is one WDM channel) " + post_powerPerChannel_dBm + " dBm. It should be between [" + edfa_minOutputPower_dBm.getDouble() + ", " 473 + edfa_maxOutputPower_dBm.getDouble() + "] dBm"; 474 if (post_powerPerChannel_dBm + numChannels_dB > edfa_maxOutputPower_dBm.getDouble() + 1E-3) 475 st += "At " + initialPosition_km + "km: Power at the EDFA output is (if all WDM channels were active) " + (post_powerPerChannel_dBm + numChannels_dB) + " dBm. It should be between [" + edfa_minOutputPower_dBm.getDouble() + ", " 476 + edfa_maxOutputPower_dBm.getDouble() + "] dBm"; 477 } else if (name.equalsIgnoreCase("PC")) 478 {} else 479 { 480 throw new RuntimeException("Unknown element type"); 481 } 482 483 res.add(st); 484 } 485 486 return res; 487 } 488 489 /** Gets all the elements in the given link or lightpath 490 * 491 * @param seqLinks list of links 492 * @return List of elements as a Quadruple object where: first is the position of the element (km), second the type of element, third the main parameter (i.e. OA=gain, PC=loss, SPAN=length, OADM=nodeID), fourth other information (i.e. 493 * OA=noiseFigure, SPAN=fiberType, OADM=noiseFigure). */ 494 private List<Quadruple<Double, String, Double, String>> getElementPositionsListPerLightpath(List<Link> seqLinks) 495 { 496 final List<Quadruple<Double, String, Double, String>> res = new LinkedList<Quadruple<Double, String, Double, String>>(); 497 double currentDistanceFromRouteInit_km = 0; 498 499 for (int index = 0; index < seqLinks.size(); index++) 500 { 501 final Link e = seqLinks.get(index); 502 int oadmCounter = 0; 503 504 final double d_e = e.getLengthInKm(); 505 final String st_edfaPositions_km = e.getAttribute("edfaPositions_km") == null ? "" : e.getAttribute("edfaPositions_km"); 506 final String st_edfaGains_dB = e.getAttribute("edfaGains_dB") == null ? "" : e.getAttribute("edfaGains_dB"); 507 final String st_edfaNoiseFigures_dB = e.getAttribute("edfaNoiseFigures_dB") == null ? "" : e.getAttribute("edfaNoiseFigures_dB"); 508 final String st_pcPositions_km = e.getAttribute("pcPositions_km") == null ? "" : e.getAttribute("pcPositions_km"); 509 final String st_pcLosses_dB = e.getAttribute("pcLosses_dB") == null ? "" : e.getAttribute("pcLosses_dB"); 510 final String st_oadmNoiseFigures_dB = e.getAttribute("oadmNoiseFigures_dB") == null ? "" : e.getAttribute("oadmNoiseFigures_dB"); 511 final String st_fiberTypes = e.getAttribute("fiberTypes") == null ? "" : e.getAttribute("fiberTypes"); 512 513 final double[] edfaPositions_km = StringUtils.toDoubleArray(StringUtils.split(st_edfaPositions_km)); 514 final double[] edfaGains_dB = StringUtils.toDoubleArray(StringUtils.split(st_edfaGains_dB)); 515 final double[] edfaNoiseFigures_dB = StringUtils.toDoubleArray(StringUtils.split(st_edfaNoiseFigures_dB)); 516 final double[] pcPositions_km = StringUtils.toDoubleArray(StringUtils.split(st_pcPositions_km)); 517 final double[] pcLosses_dB = StringUtils.toDoubleArray(StringUtils.split(st_pcLosses_dB)); 518 final double[] oadmNoiseFigures_dB = StringUtils.toDoubleArray(StringUtils.split(st_oadmNoiseFigures_dB)); 519 final String[] fiberTypes = StringUtils.split(st_fiberTypes); 520 521 /* Basic checks */ 522 if (edfaPositions_km.length != edfaGains_dB.length) 523 throw new Net2PlanException("Link: " + e + ". Number of elements in edfaPositions_km is not equal to the number of elements in edfaGains_dB"); 524 525 if (pcPositions_km.length != pcLosses_dB.length) 526 throw new Net2PlanException("Link: " + e + ". Number of elements in pcPositions_km is not equal to the number of elements in pcLosses_dB"); 527 528 for (double edfaPosition : edfaPositions_km) 529 if ((edfaPosition < 0) || (edfaPosition > d_e)) 530 throw new Net2PlanException("Link: " + e + ". Wrong OA position: " + edfaPosition + ", link length = " + d_e); 531 532 for (double pcPosition : pcPositions_km) 533 if ((pcPosition < 0) || (pcPosition > d_e)) 534 throw new Net2PlanException("Link: " + e + ". Wrong PC position: " + pcPosition + ", link length = " + d_e); 535 536 for (double noiseFigure_dB : edfaNoiseFigures_dB) 537 if ((noiseFigure_dB < Math.min(edfa_noiseFactorMinimumGain_dB.getDouble(), edfa_noiseFactorMaximumGain_dB.getDouble())) 538 || (noiseFigure_dB > Math.max(edfa_noiseFactorMinimumGain_dB.getDouble(), edfa_noiseFactorMaximumGain_dB.getDouble()))) 539 throw new RuntimeException("Bad EDFA Noise Factor, out of range"); 540 541 /* All links and lightpaths allways begin with an OADM-ADD */ 542 if (index == 0) 543 if (oadmNoiseFigures_dB.length > 0) 544 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "OADM-ADD", (double) e.getOriginNode().getId(), oadmNoiseFigures_dB[oadmCounter++] + "")); 545 else 546 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "OADM-ADD", (double) e.getOriginNode().getId(), oadm_addChannelNoiseFactor_dB.getDouble() + "")); 547 548 /* Place in a sorted form the spans, PCs and EDFAS. If PC and EDFA placed, PC goes first */ 549 final double[] pcAndEDFAPositions_km = DoubleUtils.concatenate(pcPositions_km, edfaPositions_km); 550 final int[] sortedPCAndEDFAPositionsIndexes = pcAndEDFAPositions_km.length == 0 ? new int[0] : DoubleUtils.sortIndexes(pcAndEDFAPositions_km, OrderingType.ASCENDING); 551 double posKmLastElementThisLink_km = 0; 552 int fiberSpans = 0; 553 for (int cont = 0; cont < sortedPCAndEDFAPositionsIndexes.length; cont++) 554 { 555 final int indexInCommonArray = sortedPCAndEDFAPositionsIndexes[cont]; 556 final boolean isPC = (indexInCommonArray < pcPositions_km.length); 557 final double posFromLinkInit_km = pcAndEDFAPositions_km[indexInCommonArray]; 558 final double previousSpanLength = (Math.abs(posFromLinkInit_km - posKmLastElementThisLink_km) < 1E-3) ? 0 : posFromLinkInit_km - posKmLastElementThisLink_km; 559 560 if (previousSpanLength < 0) 561 throw new RuntimeException("Bad"); 562 563 if (previousSpanLength > 0) 564 { 565 if (fiberSpans < fiberTypes.length) 566 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "SPAN", previousSpanLength, fiberTypes[fiberSpans++])); 567 else 568 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "SPAN", previousSpanLength, fiber_default_type.getString())); 569 currentDistanceFromRouteInit_km += previousSpanLength; 570 posKmLastElementThisLink_km += previousSpanLength; 571 } 572 573 if (isPC) 574 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "PC", pcLosses_dB[indexInCommonArray], null)); 575 else if (edfaNoiseFigures_dB.length > 0 && edfaNoiseFigures_dB.length < (indexInCommonArray - pcPositions_km.length)) 576 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "EDFA", edfaGains_dB[indexInCommonArray - pcPositions_km.length], edfaNoiseFigures_dB[indexInCommonArray - pcPositions_km.length] + "")); 577 else 578 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "EDFA", edfaGains_dB[indexInCommonArray - pcPositions_km.length], edfa_default_noiseFactor_dB.getDouble()+"")); 579 } 580 581 /* Last span of the link before the OADM */ 582 final double lastSpanOfLink_km = (Math.abs(d_e - posKmLastElementThisLink_km) < 1E-3) ? 0 : d_e - posKmLastElementThisLink_km; 583 584 if (lastSpanOfLink_km < 0) 585 throw new RuntimeException("Bad"); 586 587 if (lastSpanOfLink_km > 0) 588 { 589 if (fiberSpans < fiberTypes.length) 590 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "SPAN", lastSpanOfLink_km, fiberTypes[fiberSpans++])); 591 else 592 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "SPAN", lastSpanOfLink_km, fiber_default_type.getString())); 593 currentDistanceFromRouteInit_km += lastSpanOfLink_km; 594 posKmLastElementThisLink_km += lastSpanOfLink_km; 595 } 596 597 /* OADM at the end of the link */ 598 final long endNodeLink = e.getDestinationNode().getId(); 599 final long lastLink = seqLinks.get(seqLinks.size() - 1).getId(); 600 if (e.getId() == lastLink) 601 if (oadmCounter < oadmNoiseFigures_dB.length) 602 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "OADM-DROP", (double) endNodeLink, oadmNoiseFigures_dB[oadmCounter++] + "")); 603 else 604 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "OADM-DROP", (double) endNodeLink, oadm_dropChannelNoiseFactor_dB.getDouble() + "")); 605 else if (oadmCounter < oadmNoiseFigures_dB.length) 606 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "OADM-EXPRESS", (double) endNodeLink, oadmNoiseFigures_dB[oadmCounter++] + "")); 607 else 608 res.add(Quadruple.of(currentDistanceFromRouteInit_km, "OADM-EXPRESS", (double) endNodeLink, oadm_expressChannelNoiseFactor_dB.getDouble() + "")); 609 610 } 611 612 /* Check current distance equals the sum of the traversed links */ 613 double sumLinks = 0; 614 for (Link e : seqLinks) 615 sumLinks += e.getLengthInKm(); 616 617 if (Math.abs(sumLinks - currentDistanceFromRouteInit_km) > 1E-3) 618 throw new RuntimeException("Bad"); 619 return res; 620 } 621 622 private String printReport(Map<Link, List<Quadruple<Double, String, Double, String>>> elements_e, Map<Link, List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>>> impairments_e, Map<Link, List<String>> warnings_e, 623 Map<Route, List<Quadruple<Double, String, Double, String>>> elements_r, Map<Route, List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>>> impairments_r, Map<Route, List<String>> warnings_r) 624 { 625 final StringBuilder out = new StringBuilder(); 626 final DecimalFormat df_2 = new DecimalFormat("###.##"); 627 final int centralChannel = Math.floorDiv(gn_spec_nCh.getInt(), 2); 628 629 out.append("<html><body>"); 630 out.append("<head><title>WDM line engineering in multilayer (lightpath based) networks with GN calculations</title></head>"); 631 out.append("<h1>WDM line engineering report for lighptath-based networks with GN calculations</h1>"); 632 633 out.append( 634 "<h3>This report shows line engineering information for WDM links in a multilayer optical network. " + "The impairment calculations are based on the Gaussian Noise Model developed by Politecnico di Torino and their analytic formula." 635 + " Other calculations are inspired in the procedures described in the 2009 ITU-T WDM manual \"Optical fibres, cabbles and systems\".</h3>"); 636 637 out.append("<p>The report assumes that the WDM network follows the scheme:</p>"); 638 639 out.append("<ul>"); 640 out.append("<li>In the net2plan object, nodes are OADMs, links are fiber links, and routes are lightpaths: " + "WDM channels optically switched at intermediate nodes. </li>"); 641 out.append("<li>Nodes are connected by unidirectional fiber links. Fiber link distance is given by the link " + "length. Other specifications are given by fibers_XXX input parameters, each one describing the " 642 + "parameter for the fiber types specified in fibers_types, in the same order and separated by " + "spaces. The fiber can be split into spans if optical amplifers (EDFAs) and/or passive components " 643 + "(PCs) are placed along the fiber. These spans can be of different fiber types as long as they are " + "described in a link attribute called \"fiberTypes\". Must be separated by spaces and, in case that " 644 + "there were more spans than elements of the attribute, the default type given in \"fiber_default_type\" " + "would be used.</li>"); 645 out.append("<li>Optical line amplifiers (EDFAs) can be located in none, one or more positions in the fiber" + " link, separating them in different spans. EDFAs are supposed to operate in the automatic gain" 646 + " control mode. Thus, the gain is the same, whatever the number of input WDM channels. EDFA" + " positions (as distance\" in km from the link start to the EDFA location), EDFA gains (assumed in" 647 + " dB) and EDFA noise figures (in dB) are read from the \"edfaPositions_km\", \"edfaGains_dB\" and" + " \"edfaNoiseFigures_dB\" attributes of the links. The format of all attributes are the same: a" 648 + " string of numbers separated by spaces. The <i>i</i>-th number corresponding to the position/gain" + " of the <i>i</i>-th EDFA. If the attributes do not exist, it is assumed that no EDFAs are placed in this link. " 649 + "EDFA specifications are given by \"edfa_XXX\" parameters</li>"); 650 out.append("<li>There are not Dispersion compensating modules (DCMs) in the topoology, since the Gaussian Noise Model is used.</li>"); 651 out.append("<li>Passive components are described by the link attributes \"pcPositions_km\" and \"pcLosses_dB\"." + " The <i>i</i>-th number corresponding to the position/loss of the <i>i</i>-th PC. If the" 652 + " attributes do not exist, it is assumed that no PCs are placed in this link. Other specifications for Passive Components" + " will be described in teh pc_XXX input parameters.</li>"); 653 out.append("<li>Fiber links start and end in OADM modules, that permit adding, dropping and optically switch" + " individual WDM channels. OADMs have a pre-amplifier (traversed by drop and express channels) and" 654 + " a boost amplifier (traversed by add and express channels). They are supposed to equalize the" + " channel power at their outputs, to a fixed value (added and express channels will thus have the" 655 + " same power in the fibers). Also, OADMs attenuate appropriately the optical signal coming from the" + " pre-amplifier, in the drop channels, so that they fall within the receiver sensitivity range." 656 + " OADM noise figures for add, drop and express channels are given as input parameters. PMD values" + " for add, drop and express channels are computed assumming that: (i) add channel traverse a" 657 + " multiplexer and the booster, (ii) drop channels travese the pre-amplifier and a demultiplexer," + " (iii) express channels traverse the two amplifiers. The required parameters are provided in oadm_XXX parameters.</li>"); 658 out.append("<li>Each channel ends in a receiver, with specifications given by \"tp_XXX\" parameters.</li>"); 659 out.append("</ul></p>"); 660 out.append("<p>The basic checks performed are:</p>"); 661 out.append("<ul>"); 662 out.append("<li>For each link, signal power levels are within operating ranges at the oadm/edfas, both when the link has one single active channel, or when all the"); 663 out.append("\"gn_spec_nCh\" are active</li>"); 664 out.append("<li>For each route (lightpath), OSNR (Optical Signal to Noise Ration) is within the operating range at the receiver."); 665 out.append("A set of margins are considered to account to several not directly considered impairments. </li>"); 666 out.append("<li>For each route (lightpath), PMD (Polarization mode dispersion) is within the operating range at the receiver</li>"); 667 out.append("</ul></p>"); 668 669 out.append("<h2>Input Parameters</h2>"); 670 out.append("<table border='1'>"); 671 out.append("<tr><th><b>Name</b></th><th><b>Value</b></th><th><b>Description</b></th>"); 672 673 for (Triple<String, String, String> paramDef : getParameters()) 674 { 675 final String name = paramDef.getFirst(); 676 final String description = paramDef.getThird(); 677 final String value = reportParameters.get(name); 678 out.append("<tr><td>").append(name).append("</td><td>").append(value).append("</td><td>").append(description).append("</td></tr>"); 679 } 680 out.append("</table>"); 681 682 out.append("<h2>PER LINK INFORMATION SUMMARY - Signal metrics at the input of end OADM</h2>"); 683 out.append("<table border='1'>"); 684 out.append("<tr><th><b>Link #</b></th><th><b>Length (km)</b></th><th><b># EDFAs</b></th><th><b># PCs</b></th><th><b>OSNR total (dB)</b></th>" 685 + "<th><b>Power per WDM channel (dBm)</b></th><th><b>Polarization Mode Dispersion (ps)</b></th><th><b>Warnings</b></th></tr>"); 686 687 for (Link e : netPlan.getLinks()) 688 { 689 final double d_e = e.getLengthInKm(); 690 final String st_a_e = e.getOriginNode().getName(); 691 final String st_b_e = e.getDestinationNode().getName(); 692 final List<Quadruple<Double, String, Double, String>> el = elements_e.get(e); 693 final List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>> imp = impairments_e.get(e); 694 final List<String> w = warnings_e.get(e); 695 696 int numEDFAs = 0; 697 for (Quadruple<Double, String, Double, String> t : el) 698 if (t.getSecond().equalsIgnoreCase("EDFA")) 699 numEDFAs++; 700 701 int numPCs = 0; 702 for (Quadruple<Double, String, Double, String> t : el) 703 if (t.getSecond().equalsIgnoreCase("PC")) 704 numPCs++; 705 706 final Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double> impInfoInputOADM = imp.get(imp.size() - 1); 707 final Map<String, double[]> prevSpectrum = impInfoInputOADM.getFirst(); 708 final double totalOSNR_dB = OpticalImpairmentUtils.getOSNR(prevSpectrum).getThird()[centralChannel]; 709 710 final StringBuilder warnings = new StringBuilder(); 711 for (String s : w) 712 warnings.append(s); 713 714 out.append("<tr><td>").append(e).append(" (").append(st_a_e).append(" --> ").append(st_b_e).append(") </td><td>").append(df_2.format(d_e)).append("</td><td>").append(numEDFAs).append("</td><td>").append(numPCs).append("</td><td>") 715 .append((totalOSNR_dB > infinityThreshold_dB) ? "∞" : df_2.format(totalOSNR_dB)).append("</td><td>") 716 .append(df_2.format(OpticalImpairmentUtils.linear2dB(prevSpectrum.get(OpticalImpairmentUtils.stSpectrum_powerPerChannel_W)[centralChannel] * 1e3))).append("</td><td>").append(df_2.format(Math.sqrt(impInfoInputOADM.getSecond()))) 717 .append("</td><td>").append(warnings).append("</td></tr>"); 718 } 719 out.append("</table>"); 720 721 out.append("<h2>PER ROUTE INFORMATION SUMMARY - Signal metrics at the input of last OADM</h2>"); 722 out.append("<table border='1'>"); 723 out.append("<tr><th><b>Route #</b></th><th><b>Length (km)</b></th><th><b># EDFAs</b></th><th><b># PCs</b></th>" 724 + "<th><b>OSNR total (dB)</b></th><th><b>Power per WDM channel (dBm)</b></th><th><b>Polarization Mode Dispersion (ps)</b></th><th><b>Warnings</b></th></tr>"); 725 for (Route r : netPlan.getRoutes()) 726 { 727 final double d_r = r.getLengthInKm(); 728 final String st_a_r = r.getIngressNode().getName(); 729 final String st_b_r = r.getEgressNode().getName(); 730 final List<Quadruple<Double, String, Double, String>> el = elements_r.get(r); 731 final List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>> imp = impairments_r.get(r); 732 final List<String> w = warnings_r.get(r); 733 734 int numEDFAs = 0; 735 for (Quadruple<Double, String, Double, String> t : el) 736 if (t.getSecond().equalsIgnoreCase("EDFA")) 737 numEDFAs++; 738 739 int numPCs = 0; 740 for (Quadruple<Double, String, Double, String> t : el) 741 if (t.getSecond().equalsIgnoreCase("PC")) 742 numPCs++; 743 744 final Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double> impInfoInputOADM = imp.get(imp.size() - 1); 745 final Map<String, double[]> preSpectrum = impInfoInputOADM.getFirst(); 746 final double totalOSNR_dB = OpticalImpairmentUtils.getOSNR(preSpectrum).getThird()[centralChannel]; 747 748 final StringBuilder warnings = new StringBuilder(); 749 for (String s : w) 750 warnings.append(s); 751 752 out.append("<tr><td>").append(r).append(" (").append(st_a_r).append(" --> ").append(st_b_r).append(") </td><td>").append(df_2.format(d_r)).append("</td><td>").append(numEDFAs).append("</td><td>").append(numPCs).append("</td><td>") 753 .append((totalOSNR_dB > infinityThreshold_dB) ? "∞" : df_2.format(totalOSNR_dB)).append("</td><td>") 754 .append(df_2.format(OpticalImpairmentUtils.linear2dB(preSpectrum.get(OpticalImpairmentUtils.stSpectrum_powerPerChannel_W)[centralChannel] * 1e3))).append("</td><td>").append(df_2.format(Math.sqrt(impInfoInputOADM.getSecond()))) 755 .append("</td><td>").append(warnings.toString()).append("</td>" + "</tr>"); 756 757 } 758 out.append("</table>"); 759 760 out.append("<h2>PER-LINK DETAILED INFORMATION </h2>"); 761 out.append("<p>Number of links: ").append(netPlan.getNumberOfLinks()).append("</p>"); 762 763 for (Link e : netPlan.getLinks()) 764 { 765 final double d_e = e.getLengthInKm(); 766 final String st_a_e = e.getOriginNode().getName(); 767 final String st_b_e = e.getDestinationNode().getName(); 768 final List<Quadruple<Double, String, Double, String>> el = elements_e.get(e); 769 final List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>> imp = impairments_e.get(e); 770 final List<String> w = warnings_e.get(e); 771 final String st_edfaPositions_km = e.getAttribute("edfaPositions_km") == null ? "" : e.getAttribute("edfaPositions_km"); 772 final String st_edfaGains_dB = e.getAttribute("edfaGains_dB") == null ? "" : e.getAttribute("edfaGains_dB"); 773 final String st_edfaNoiseFigures_dB = e.getAttribute("edfaNoiseFigures_dB") == null ? "" : e.getAttribute("edfaNoiseFigures_dB"); 774 final String st_pcPositions_km = e.getAttribute("pcPositions_km") == null ? "" : e.getAttribute("pcPositions_km"); 775 final String st_pcLosses_dB = e.getAttribute("pcLosses_dB") == null ? "" : e.getAttribute("pcLosses_dB"); 776 777 out.append("<h3>LINK # ").append(e).append(" (").append(st_a_e).append(" --> ").append(st_b_e).append(")</h3>"); 778 out.append("<table border=\"1\">"); 779 out.append("<caption>Link information</caption>"); 780 out.append("<tr><td>Link length (km)</td><td>").append(d_e).append("</td></tr>"); 781 out.append("<tr><td>EDFA positions (km)</td><td>").append(st_edfaPositions_km).append("</td></tr>"); 782 out.append("<tr><td>EDFA gains (dB)</td><td>").append(st_edfaGains_dB).append("</td></tr>"); 783 out.append("<tr><td>EDFA Noise Figures (dB)</td><td>").append(st_edfaNoiseFigures_dB).append("</td></tr>"); 784 out.append("<tr><td>PC positions (km)</td><td>").append(st_pcPositions_km).append("</td></tr>"); 785 out.append("<tr><td>PC losses (dB)</td><td>").append(st_pcLosses_dB).append("</td></tr>"); 786 out.append("</table>"); 787 788 out.append("<table border=\"1\">"); 789 out.append("<caption>Signal metrics evolution at the output of each element.</caption>"); 790 out.append("<tr><th><b>Position (km)</b></th><th><b>Position (description)</b></th><th><b>OSNR total(dB)</b></th>" 791 + "<th><b>Power per WDM channel (dBm)</b></th><th><b>Polarization Mode Dispersion (ps)</b></th><th><b>Warnings</b></th></tr>"); 792 793 final Iterator<Quadruple<Double, String, Double, String>> it_el = el.iterator(); 794 final Iterator<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>> it_imp = imp.iterator(); 795 final Iterator<String> it_w = w.iterator(); 796 while (it_el.hasNext()) 797 { 798 final Quadruple<Double, String, Double, String> this_el = it_el.next(); 799 final Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double> this_imp = it_imp.next(); 800 final String this_warnings = it_w.next(); 801 802 final double pos_km = this_el.getFirst(); 803 String elementType = this_el.getSecond(); 804 final double elementData = this_el.getThird(); 805 final String elementAuxData = this_el.getFourth(); 806 807 final Map<String, double[]> postSpectrum = this_imp.getThird(); 808 final double totalOSNR_dB = OpticalImpairmentUtils.getOSNR(postSpectrum).getThird()[centralChannel]; 809 810 if (elementType.equalsIgnoreCase("EDFA")) 811 elementType += " (G: " + elementData + " dB, F: " + elementAuxData + " dB)"; 812 else if (elementType.equalsIgnoreCase("SPAN")) 813 elementType += " (Type: " + elementAuxData + ", " + elementData + " km)"; 814 else if (elementType.equalsIgnoreCase("PC")) 815 elementType += " (L: " + elementData + " dB)"; 816 817 out.append("<tr><td>").append(df_2.format(pos_km)).append("</td><td>" + "Output of ").append(elementType).append("</td><td>").append((totalOSNR_dB > infinityThreshold_dB) ? "∞" : df_2.format(totalOSNR_dB)).append("</td><td>") 818 .append(df_2.format(OpticalImpairmentUtils.linear2dB(postSpectrum.get(OpticalImpairmentUtils.stSpectrum_powerPerChannel_W)[centralChannel] * 1e3))).append("</td><td>").append(df_2.format(Math.sqrt(this_imp.getSecond()))) 819 .append("</td><td>").append(this_warnings).append("</td>" + "</tr>"); 820 821 } 822 out.append("</table>"); 823 } 824 825 out.append("<h2>PER-LIGHTPATH DETAILED INFORMATION</h2>"); 826 out.append("<p>Number of lightpaths: ").append(netPlan.getNumberOfRoutes()).append("</p>"); 827 828 for (Route r : netPlan.getRoutes()) 829 { 830 final double d_r = r.getLengthInKm(); 831 final String st_a_r = r.getIngressNode().getName(); 832 final String st_b_r = r.getEgressNode().getName(); 833 final List<Quadruple<Double, String, Double, String>> el = elements_r.get(r); 834 final List<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>> imp = impairments_r.get(r); 835 final List<String> w = warnings_r.get(r); 836 837 out.append("<h3>ROUTE # ").append(r).append(" (").append(st_a_r).append(" --> ").append(st_b_r).append("), Length: ").append(d_r).append(" km</h3>"); 838 out.append("<table border=\"1\">"); 839 out.append("<caption>Signal metrics evolution</caption>"); 840 out.append("<tr><th><b>Position (km)</b></th><th><b>Position (description)</b></th><th><b>OSNR total (dB)</b></th>" 841 + "<th><b>Power per WDM channel (dBm)</b></th><th><b>Polarization Mode Dispersion (ps)</b></th><th><b>Warnings</b></th></tr>"); 842 843 final Iterator<Quadruple<Double, String, Double, String>> it_el = el.iterator(); 844 final Iterator<Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double>> it_imp = imp.iterator(); 845 final Iterator<String> it_w = w.iterator(); 846 while (it_el.hasNext()) 847 { 848 final Quadruple<Double, String, Double, String> this_el = it_el.next(); 849 final Quadruple<Map<String, double[]>, Double, Map<String, double[]>, Double> this_imp = it_imp.next(); 850 final String this_warnings = it_w.next(); 851 852 final double pos_km = this_el.getFirst(); 853 String elementType = this_el.getSecond(); 854 final double elementData = this_el.getThird(); 855 final String elementAuxData = this_el.getFourth(); 856 857 final Map<String, double[]> postSpectrum = this_imp.getThird(); 858 final double totalOSNR_dB = OpticalImpairmentUtils.getOSNR(postSpectrum).getThird()[centralChannel]; 859 860 if (elementType.equalsIgnoreCase("EDFA")) 861 elementType += " (G: " + elementData + " dB, NF: " + elementAuxData + " dB)"; 862 else if (elementType.equalsIgnoreCase("SPAN")) 863 elementType += " (Type: " + elementAuxData + ", l:" + elementData + " km)"; 864 else if (elementType.equalsIgnoreCase("PC")) 865 elementType += " (L: " + elementData + " dB)"; 866 867 out.append("<tr><td>").append(df_2.format(pos_km)).append("</td><td>" + "Output of ").append(elementType).append("</td><td>").append((totalOSNR_dB > infinityThreshold_dB) ? "∞" : df_2.format(totalOSNR_dB)).append("</td><td>") 868 .append(df_2.format(OpticalImpairmentUtils.linear2dB(postSpectrum.get(OpticalImpairmentUtils.stSpectrum_powerPerChannel_W)[centralChannel] * 1e3))).append("</td><td>").append(df_2.format(Math.sqrt(this_imp.getSecond()))) 869 .append("</td><td>").append(this_warnings).append("</td>" + "</tr>"); 870 871 } 872 873 out.append("</table>"); 874 } 875 876 out.append("</body></html>"); 877 return out.toString(); 878 } 879 880}