mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-11-01 18:47:48 +00:00
Merge pull request #224 from Orange-OpenSource/auto_design3
Auto design3
This commit is contained in:
@@ -97,13 +97,18 @@ def select_edfa(raman_allowed, gain_target, power_target, equipment, uid):
|
|||||||
"""amplifer selection algorithm
|
"""amplifer selection algorithm
|
||||||
@Orange Jean-Luc Augé
|
@Orange Jean-Luc Augé
|
||||||
"""
|
"""
|
||||||
Edfa_list = namedtuple('Edfa_list', 'raman variety power gain_min nf')
|
Edfa_list = namedtuple('Edfa_list', 'variety power gain_min nf')
|
||||||
TARGET_EXTENDED_GAIN = equipment['Span']['default'].target_extended_gain
|
TARGET_EXTENDED_GAIN = equipment['Span']['default'].target_extended_gain
|
||||||
edfa_dict = equipment['Edfa']
|
edfa_dict = equipment['Edfa']
|
||||||
pin = power_target - gain_target
|
pin = power_target - gain_target
|
||||||
|
|
||||||
|
#create 2 list of available amplifiers with relevant attributs 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(
|
edfa_list = [Edfa_list(
|
||||||
raman=edfa.raman,
|
|
||||||
variety=edfa_variety,
|
variety=edfa_variety,
|
||||||
power=min(
|
power=min(
|
||||||
pin
|
pin
|
||||||
@@ -117,49 +122,75 @@ def select_edfa(raman_allowed, gain_target, power_target, equipment, uid):
|
|||||||
-edfa.gain_min,
|
-edfa.gain_min,
|
||||||
nf=edfa_nf(gain_target, edfa_variety, equipment)) \
|
nf=edfa_nf(gain_target, edfa_variety, equipment)) \
|
||||||
for edfa_variety, edfa in edfa_dict.items()
|
for edfa_variety, edfa in edfa_dict.items()
|
||||||
if edfa.allowed_for_design]
|
if (edfa.allowed_for_design and not edfa.raman)]
|
||||||
|
|
||||||
#filter on raman restriction
|
#consider a Raman list because of different gain_min requirement:
|
||||||
raman_filter = lambda edfa: (edfa.raman and raman_allowed) or not edfa.raman
|
#do not allow extended gain min for Raman
|
||||||
edfa_list = list(filter(raman_filter, edfa_list))
|
raman_list = [Edfa_list(
|
||||||
#print(f'\n{uid}, gain {gain_target}, {power_target}')
|
variety=edfa_variety,
|
||||||
#print('edfa',edfa_list)
|
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:
|
#filter on min gain limitation:
|
||||||
#consider gain_target+3 to allow some operation below min gain
|
acceptable_gain_min_list = [x for x in amp_list if x.gain_min>0]
|
||||||
#(~counterpart to the extended gain range)
|
|
||||||
acceptable_gain_min_list = \
|
|
||||||
list(filter(lambda x : x.gain_min>0, edfa_list))
|
|
||||||
if len(acceptable_gain_min_list) < 1:
|
if len(acceptable_gain_min_list) < 1:
|
||||||
#do not take this empty list into account for the rest of the code
|
#do not take this empty list into account for the rest of the code
|
||||||
#but issue a warning to the user
|
#but issue a warning to the user and do not consider Raman
|
||||||
print(
|
#Raman below min gain should not be allowed because i is meant to be a design requirement
|
||||||
f'\x1b[1;31;40m'\
|
#and raman padding at the amplifier input is impossible!
|
||||||
+ f'WARNING: target gain in node {uid} is below all available amplifiers min gain: \
|
|
||||||
amplifier input padding will be assumed, consider increase fiber padding instead'\
|
|
||||||
+ '\x1b[0m'
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
edfa_list = acceptable_gain_min_list
|
|
||||||
#print('gain_min', acceptable_gain_min_list)
|
|
||||||
|
|
||||||
#filter on max power limitation:
|
if len(edfa_list) < 1:
|
||||||
acceptable_power_list = \
|
print(
|
||||||
list(filter(lambda x : x.power>=0, edfa_list))
|
f'\x1b[1;31;40m'\
|
||||||
|
+ f'CRITICAL _ ABORT: auto_design could not find any amplifier \
|
||||||
|
to satisfy min gain requirement in node {uid} \
|
||||||
|
please increase span fiber padding'\
|
||||||
|
+ '\x1b[0m'
|
||||||
|
)
|
||||||
|
exit()
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f'\x1b[1;31;40m'\
|
||||||
|
+ f'WARNING: target gain in node {uid} is below all available amplifiers min gain: \
|
||||||
|
amplifier input padding will be assumed, consider increase span fiber padding instead'\
|
||||||
|
+ '\x1b[0m'
|
||||||
|
)
|
||||||
|
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:
|
if len(acceptable_power_list) < 1:
|
||||||
#no amplifier satisfies the required power, so pick the highest power:
|
#no amplifier satisfies the required power, so pick the highest power(s):
|
||||||
power_max = max(edfa_list, key=attrgetter('power')).power
|
power_max = max(acceptable_gain_min_list, key=attrgetter('power')).power
|
||||||
#pick up all amplifiers that share this max gain:
|
#check and pick if other amplifiers may have a similar gain/power
|
||||||
acceptable_power_list = \
|
#allow a 0.3dB power range
|
||||||
list(filter(lambda x : x.power-power_max>-0.3, edfa_list))
|
#this allows to chose an amplifier with a better NF subsequentely
|
||||||
#print('power', acceptable_power_list)
|
acceptable_power_list = [x for x in acceptable_gain_min_list
|
||||||
|
if x.power-power_max>-0.3]
|
||||||
|
|
||||||
# debug:
|
|
||||||
# print(gain_target, power_target, '=>\n',acceptable_power_list)
|
|
||||||
|
|
||||||
# gain and power requirements are resolved,
|
# gain and power requirements are resolved,
|
||||||
# =>chose the amp with the best NF among the acceptable ones:
|
# =>chose the amp with the best NF among the acceptable ones:
|
||||||
selected_edfa = min(acceptable_power_list, key=attrgetter('nf')) #filter on NF
|
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)
|
power_reduction = round(min(selected_edfa.power, 0),2)
|
||||||
if power_reduction < -0.5:
|
if power_reduction < -0.5:
|
||||||
print(
|
print(
|
||||||
@@ -168,7 +199,8 @@ def select_edfa(raman_allowed, gain_target, power_target, equipment, uid):
|
|||||||
is beyond all available amplifiers capabilities and/or extended_gain_range:\n\
|
is beyond all available amplifiers capabilities and/or extended_gain_range:\n\
|
||||||
a power reduction of {power_reduction} is applied\n'\
|
a power reduction of {power_reduction} is applied\n'\
|
||||||
+ '\x1b[0m'
|
+ '\x1b[0m'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
return selected_edfa.variety, power_reduction
|
return selected_edfa.variety, power_reduction
|
||||||
|
|
||||||
@@ -295,8 +327,7 @@ def set_egress_amplifier(network, roadm, equipment, pref_total_db):
|
|||||||
#go through all nodes in the OMS (loop until next Roadm instance)
|
#go through all nodes in the OMS (loop until next Roadm instance)
|
||||||
if isinstance(node, Edfa):
|
if isinstance(node, Edfa):
|
||||||
node_loss = span_loss(network, prev_node)
|
node_loss = span_loss(network, prev_node)
|
||||||
if node.out_voa:
|
voa = node.out_voa if node.out_voa else 0
|
||||||
voa = node.out_voa
|
|
||||||
if node.delta_p is None:
|
if node.delta_p is None:
|
||||||
dp = target_power(network, next_node, equipment)
|
dp = target_power(network, next_node, equipment)
|
||||||
else:
|
else:
|
||||||
@@ -308,20 +339,28 @@ def set_egress_amplifier(network, roadm, equipment, pref_total_db):
|
|||||||
gain_target = node.effective_gain
|
gain_target = node.effective_gain
|
||||||
dp = prev_dp - node_loss + gain_target
|
dp = prev_dp - node_loss + gain_target
|
||||||
#print(node.delta_p, dp, gain_target)
|
#print(node.delta_p, dp, gain_target)
|
||||||
power_target = pref_total_db + dp
|
power_target = pref_total_db + dp
|
||||||
|
|
||||||
|
raman_allowed = False
|
||||||
|
if isinstance(prev_node, Fiber):
|
||||||
|
max_fiber_lineic_loss_for_raman = \
|
||||||
|
equipment['Span']['default'].max_fiber_lineic_loss_for_raman
|
||||||
|
raman_allowed = prev_node.params.loss_coef < max_fiber_lineic_loss_for_raman
|
||||||
|
|
||||||
if node.params.type_variety == '' :
|
if node.params.type_variety == '' :
|
||||||
raman_allowed = False
|
|
||||||
if isinstance(prev_node, Fiber):
|
|
||||||
max_fiber_lineic_loss_for_raman = \
|
|
||||||
equipment['Span']['default'].max_fiber_lineic_loss_for_raman
|
|
||||||
raman_allowed = prev_node.params.loss_coef < max_fiber_lineic_loss_for_raman
|
|
||||||
edfa_variety, power_reduction = select_edfa(raman_allowed,
|
edfa_variety, power_reduction = select_edfa(raman_allowed,
|
||||||
gain_target, power_target, equipment, node.uid)
|
gain_target, power_target, equipment, node.uid)
|
||||||
extra_params = equipment['Edfa'][edfa_variety]
|
extra_params = equipment['Edfa'][edfa_variety]
|
||||||
node.params.update_params(extra_params.__dict__)
|
node.params.update_params(extra_params.__dict__)
|
||||||
dp += power_reduction
|
dp += power_reduction
|
||||||
gain_target += power_reduction
|
gain_target += power_reduction
|
||||||
|
elif node.params.raman and not raman_allowed:
|
||||||
|
print(
|
||||||
|
f'\x1b[1;31;40m'\
|
||||||
|
+ f'WARNING: raman is used in node {node.uid}\n \
|
||||||
|
but fiber lineic loss is above threshold\n'\
|
||||||
|
+ '\x1b[0m'
|
||||||
|
)
|
||||||
|
|
||||||
node.delta_p = dp if power_mode else None
|
node.delta_p = dp if power_mode else None
|
||||||
node.effective_gain = gain_target
|
node.effective_gain = gain_target
|
||||||
@@ -436,13 +475,13 @@ def split_fiber(network, fiber, bounds, target_length, equipment):
|
|||||||
edgeweight = 0.01
|
edgeweight = 0.01
|
||||||
network.add_edge(prev_node, next_node, weight = edgeweight)
|
network.add_edge(prev_node, next_node, weight = edgeweight)
|
||||||
|
|
||||||
def add_connector_loss(fibers, con_in, con_out, EOL):
|
def add_connector_loss(network, fibers, default_con_in, default_con_out, EOL):
|
||||||
for fiber in fibers:
|
for fiber in fibers:
|
||||||
if fiber.con_in is None: fiber.con_in = con_in
|
if fiber.con_in is None: fiber.con_in = default_con_in
|
||||||
if fiber.con_out is None:
|
if fiber.con_out is None: fiber.con_out = default_con_out
|
||||||
fiber.con_out = con_out #con_out includes EOL
|
next_node = next(n for n in network.successors(fiber))
|
||||||
else:
|
if not isinstance(next_node, Fused):
|
||||||
fiber.con_out = fiber.con_out+EOL
|
fiber.con_out += EOL
|
||||||
|
|
||||||
def add_fiber_padding(network, fibers, padding):
|
def add_fiber_padding(network, fibers, padding):
|
||||||
"""last_fibers = (fiber for n in network.nodes()
|
"""last_fibers = (fiber for n in network.nodes()
|
||||||
@@ -473,13 +512,13 @@ def build_network(network, equipment, pref_ch_db, pref_total_db):
|
|||||||
min_length = max(int(default_span_data.padding/0.2*1e3),50_000)
|
min_length = max(int(default_span_data.padding/0.2*1e3),50_000)
|
||||||
bounds = range(min_length, max_length)
|
bounds = range(min_length, max_length)
|
||||||
target_length = max(min_length, 90_000)
|
target_length = max(min_length, 90_000)
|
||||||
con_in = default_span_data.con_in
|
default_con_in = default_span_data.con_in
|
||||||
con_out = default_span_data.con_out + default_span_data.EOL
|
default_con_out = default_span_data.con_out
|
||||||
padding = default_span_data.padding
|
padding = default_span_data.padding
|
||||||
|
|
||||||
#set raodm loss for gain_mode before to build network
|
#set roadm loss for gain_mode before to build network
|
||||||
fibers = [f for f in network.nodes() if isinstance(f, Fiber)]
|
fibers = [f for f in network.nodes() if isinstance(f, Fiber)]
|
||||||
add_connector_loss(fibers, con_in, con_out, default_span_data.EOL)
|
add_connector_loss(network, fibers, default_con_in, default_con_out, default_span_data.EOL)
|
||||||
add_fiber_padding(network, fibers, padding)
|
add_fiber_padding(network, fibers, padding)
|
||||||
# don't group split fiber and add amp in the same loop
|
# don't group split fiber and add amp in the same loop
|
||||||
# =>for code clarity (at the expense of speed):
|
# =>for code clarity (at the expense of speed):
|
||||||
|
|||||||
@@ -418,7 +418,7 @@ def propagate2(path, req, equipment, show=False):
|
|||||||
path[-1].update_snr(req.tx_osnr, equipment['Roadm']['default'].add_drop_osnr)
|
path[-1].update_snr(req.tx_osnr, equipment['Roadm']['default'].add_drop_osnr)
|
||||||
return infos
|
return infos
|
||||||
|
|
||||||
def propagate_and_optimize_mode(path, req, equipment):
|
def propagate_and_optimize_mode(path, req, equipment, show=False):
|
||||||
# if mode is unknown : loops on the modes starting from the highest baudrate fiting in the
|
# if mode is unknown : loops on the modes starting from the highest baudrate fiting in the
|
||||||
# step 1: create an ordered list of modes based on baudrate
|
# step 1: create an ordered list of modes based on baudrate
|
||||||
baudrate_to_explore = list(set([m['baud_rate'] for m in equipment['Transceiver'][req.tsp].mode
|
baudrate_to_explore = list(set([m['baud_rate'] for m in equipment['Transceiver'][req.tsp].mode
|
||||||
@@ -442,6 +442,8 @@ def propagate_and_optimize_mode(path, req, equipment):
|
|||||||
b, req.power, req.spacing)
|
b, req.power, req.spacing)
|
||||||
for el in path:
|
for el in path:
|
||||||
si = el(si)
|
si = el(si)
|
||||||
|
if show:
|
||||||
|
print(el)
|
||||||
for m in modes_to_explore :
|
for m in modes_to_explore :
|
||||||
if path[-1].snr is not None:
|
if path[-1].snr is not None:
|
||||||
path[-1].update_snr(m['tx_osnr'], equipment['Roadm']['default'].add_drop_osnr)
|
path[-1].update_snr(m['tx_osnr'], equipment['Roadm']['default'].add_drop_osnr)
|
||||||
|
|||||||
Reference in New Issue
Block a user