def convert_length(value, units): """Convert length into basic SI units >>> convert_length(1, 'km') 1000.0 >>> convert_length(2.0, 'km') 2000.0 >>> convert_length(123, 'm') 123.0 >>> convert_length(123.0, 'm') 123.0 >>> convert_length(42.1, 'km') 42100.0 >>> convert_length(666, 'yards') Traceback (most recent call last): ... gnpy.core.exceptions.ConfigurationError: Cannot convert length in "yards" into meters """ if units == 'm': return value * 1e0 elif units == 'km': return value * 1e3 else: raise ConfigurationError( f'Cannot convert length in "{units}" into meters')
def _cls_for(equipment_type): if equipment_type == 'Edfa': return elements.Edfa if equipment_type == 'Fused': return elements.Fused elif equipment_type == 'Roadm': return elements.Roadm elif equipment_type == 'Transceiver': return elements.Transceiver elif equipment_type == 'Fiber': return elements.Fiber elif equipment_type == 'RamanFiber': return elements.RamanFiber else: raise ConfigurationError(f'Unknown network equipment "{equipment_type}"')
def target_power(network, node, equipment): # get_fiber_dp if isinstance(node, elements.Roadm): return 0 SPAN_LOSS_REF = 20 POWER_SLOPE = 0.3 dp_range = list(equipment['Span']['default'].delta_power_range_db) node_loss = span_loss(network, node) try: dp = round2float((node_loss - SPAN_LOSS_REF) * POWER_SLOPE, dp_range[2]) dp = max(dp_range[0], dp) dp = min(dp_range[1], dp) except IndexError: raise ConfigurationError(f'invalid delta_power_range_db definition in eqpt_config[Span]' f'delta_power_range_db: [lower_bound, upper_bound, step]') return dp
def network_from_json(json_data, equipment): # NOTE|dutc: we could use the following, but it would tie our data format # too closely to the graph library # from networkx import node_link_graph g = DiGraph() for el_config in json_data['elements']: typ = el_config.pop('type') variety = el_config.pop('type_variety', 'default') cls = _cls_for(typ) if typ == 'Fused': # well, there's no variety for the 'Fused' node type pass elif variety in equipment[typ]: extra_params = equipment[typ][variety] temp = el_config.setdefault('params', {}) temp = merge_amplifier_restrictions(temp, extra_params.__dict__) el_config['params'] = temp el_config['type_variety'] = variety elif (typ in ['Fiber', 'RamanFiber' ]) or (typ == 'Edfa' and variety not in ['default', '']): raise ConfigurationError( f'The {typ} of variety type {variety} was not recognized:' '\nplease check it is properly defined in the eqpt_config json file' ) el = cls(**el_config) g.add_node(el) nodes = {k.uid: k for k in g.nodes()} for cx in json_data['connections']: from_node, to_node = cx['from_node'], cx['to_node'] try: if isinstance(nodes[from_node], elements.Fiber): edge_length = nodes[from_node].params.length else: edge_length = 0.01 g.add_edge(nodes[from_node], nodes[to_node], weight=edge_length) except KeyError: raise NetworkTopologyError( f'can not find {from_node} or {to_node} defined in {cx}') return g
def select_edfa(raman_allowed, gain_target, power_target, equipment, uid, restrictions=None): """amplifer selection algorithm @Orange Jean-Luc Augé """ Edfa_list = namedtuple('Edfa_list', 'variety power gain_min nf') TARGET_EXTENDED_GAIN = equipment['Span']['default'].target_extended_gain # for roadm restriction only: create a dict including not allowed for design amps # because main use case is to have specific radm amp which are not allowed for ILA # with the auto design edfa_dict = { name: amp for (name, amp) in equipment['Edfa'].items() if restrictions is None or name in restrictions } pin = power_target - gain_target # create 2 list of available amplifiers with relevant attributes for their selection # edfa list with: # extended gain min allowance of 3dB: could be parametrized, but a bit complex # extended gain max allowance TARGET_EXTENDED_GAIN is coming from eqpt_config.json # power attribut include power AND gain limitations edfa_list = [ Edfa_list(variety=edfa_variety, power=min(pin + edfa.gain_flatmax + TARGET_EXTENDED_GAIN, edfa.p_max) - power_target, gain_min=gain_target + 3 - edfa.gain_min, nf=edfa_nf(gain_target, edfa_variety, equipment)) for edfa_variety, edfa in edfa_dict.items() if ((edfa.allowed_for_design or restrictions is not None) and not edfa.raman) ] # consider a Raman list because of different gain_min requirement: # do not allow extended gain min for Raman raman_list = [Edfa_list( variety=edfa_variety, power=min( pin + edfa.gain_flatmax + TARGET_EXTENDED_GAIN, edfa.p_max ) - power_target, gain_min=gain_target - edfa.gain_min, nf=edfa_nf(gain_target, edfa_variety, equipment)) for edfa_variety, edfa in edfa_dict.items() if (edfa.allowed_for_design and edfa.raman)] \ if raman_allowed else [] # merge raman and edfa lists amp_list = edfa_list + raman_list # filter on min gain limitation: acceptable_gain_min_list = [x for x in amp_list if x.gain_min > 0] if len(acceptable_gain_min_list) < 1: # do not take this empty list into account for the rest of the code # but issue a warning to the user and do not consider Raman # Raman below min gain should not be allowed because i is meant to be a design requirement # and raman padding at the amplifier input is impossible! if len(edfa_list) < 1: raise ConfigurationError( f'auto_design could not find any amplifier \ to satisfy min gain requirement in node {uid} \ please increase span fiber padding') else: # TODO: convert to logging print( f'{ansi_escapes.red}WARNING:{ansi_escapes.reset} target gain in node {uid} is below all available amplifiers min gain: \ amplifier input padding will be assumed, consider increase span fiber padding instead' ) acceptable_gain_min_list = edfa_list # filter on gain+power limitation: # this list checks both the gain and the power requirement # because of the way .power is calculated in the list acceptable_power_list = [ x for x in acceptable_gain_min_list if x.power > 0 ] if len(acceptable_power_list) < 1: # no amplifier satisfies the required power, so pick the highest power(s): power_max = max(acceptable_gain_min_list, key=attrgetter('power')).power # check and pick if other amplifiers may have a similar gain/power # allow a 0.3dB power range # this allows to chose an amplifier with a better NF subsequentely acceptable_power_list = [ x for x in acceptable_gain_min_list if x.power - power_max > -0.3 ] # gain and power requirements are resolved, # =>chose the amp with the best NF among the acceptable ones: selected_edfa = min(acceptable_power_list, key=attrgetter('nf')) # filter on NF # check what are the gain and power limitations of this amp power_reduction = round(min(selected_edfa.power, 0), 2) if power_reduction < -0.5: print( f'{ansi_escapes.red}WARNING:{ansi_escapes.reset} target gain and power in node {uid}\n \ is beyond all available amplifiers capabilities and/or extended_gain_range:\n\ a power reduction of {power_reduction} is applied\n') return selected_edfa.variety, power_reduction