# Path: openlego/utils/xml_utils.py
# def xml_safe_create_element(
#         tree,       # type: etree._ElementTree
#         xpath,      # type: str
#         value=None  # type: Optional[Union[str, int, float, List[Union[str, int, float]], np.ndarray]]
# ):
#     # type: (...) -> etree._Element
#     """Create an element at the given XML XPath with the given value.
# 
#     This method ensures that all elements implied by the given X-Path exist.
# 
#     Supplying a value is optional. If no value is supplied an empty XML node is created at the deepest level implied by
#     the XPath.
# 
#     Parameters
#     ----------
#         tree : :obj:`etree._ElementTree`
#             `etree._ElementTree` in which to create the element.
# 
#         xpath : str
#             XPath to ensure.
# 
#         value : str or int or float or list of str or list of int or list of float or :obj:`np.ndarray`
#             Optional value to write at the deepest node of the ensured XPath.
# 
#     Returns
#     -------
#         :obj:`etree._Element`
#             Instance of `etree._Element` corresponding to the newly created element.
#     """
#     # Split the xpath to get the intermediate nodes as a list
#     xpath_list = xpath.split('/')
#     n = len(xpath_list)
# 
#     # Loop over the elements in the XPath from tip to root until the XPath is found to already exist
#     elem = None
#     i = 0
#     for i in range(0, n - 1):
#         xpath = '/'.join(xpath_list[0:(n - i)])
#         try:
#             elems = tree.xpath(xpath)
#             if len(elems):
#                 elem = elems[0]
#                 break
#         except etree.XPathError:
#             raise ValueError('Specified XPath {} is invalid.'.format(xpath))
# 
#     # If no existing element was found the root elements of the tree and XPath don't match
#     if elem is None:
#         raise ValueError("Specified XPath is incompatible with the given XML tree: root tags don't match")
# 
#     # Loop over the part of the XPath beyond this point and create all intermediate elements including attributes
#     for j in range(n - i, n):
#         tag = xpath_list[j]
# 
#         # See if this node has an integer index specified
#         match_ind = re_ind.search(tag)
#         if match_ind:
#             tag = tag[:match_ind.start()] + tag[match_ind.end():]
#             index = int(match_ind.group(1)) - 1
#         else:
#             index = 0
# 
#         # Find any attributes at this node
#         attrib = {}
#         match_attr = list(re_atr.finditer(tag))
#         if match_attr:
#             # Loop over all attributes on this node
#             for match in match_attr:
#                 if match.start() < len(tag):
#                     tag = tag[:match.start()]
#                 attrib.update({match.group(1): match.group(2)})
# 
#         # Check if there are siblings with the same name
#         siblings = elem.findall(tag)
#         n_siblings = len(siblings)
# 
#         # Check if there's a sibling with the same name at this index without conflicting attributes
#         if index < n_siblings and not any(
#                 [siblings[index].attrib[key] != attrib[key] for key in attrib.keys() if key in siblings[index].attrib]):
#             # If so, use it instead of adding a new one
#             siblings[index].attrib.update(attrib)
#             elem = siblings[index]
#         elif index <= n_siblings:
#             # In this case just append a new element
#             _elem = etree.Element(tag, attrib)
#             elem.append(_elem)
#             elem = _elem
#         else:
#             # In the last case, insert as many empty siblings until this node's index
#             sibling = None
#             for i in range(index - n_siblings):
#                 _sibling = etree.Element(tag)
#                 if i == 0:
#                     if not n_siblings:
#                         elem.append(_sibling)
#                     else:
#                         siblings[-1].addnext(_sibling)
#                 else:
#                     sibling.addnext(_sibling)
#                 sibling = _sibling
# 
#             # Finally at a new element at the right index with all attributes
#             elem = etree.Element(tag, attrib)
#             sibling.addnext(elem)
# 
#         # Finally we can update the current XPath, since it has been assured to exist at this point
#         xpath = '/'.join([xpath, xpath_list[j]])
# 
#     # If a value was supplied assign it to the deepest element in the XPath
#     if value is not None:
#         value_to_xml(elem, value)
# 
#     return elem


import math
import argparse
from lxml import etree
from openlego.utils.xml_utils import xml_safe_create_element
    y2 = sqrt(y1) + z1 + z2
    (one execution)

Call using:
    python d12.py input.xml output.xml

The script is written for Python 2.7!

Copyright 2019, DLR, Jasper Bussemaker.
Licence: MIT
"""


def run(input_xml_file, output_xml_file):
    # Load input file
    tree = etree.parse(input_xml_file)
    root = tree.getroot()

    # Load input parameters for this discipline
    x1 = float(root.find('./variables/x1').text)
    z1 = float(root.find('./variables/z1').text)
    z2 = float(root.find('./variables/z2').text)
    y2 = float(root.find('./analyses/y2').text)

    # "Run" the discipline calculations
    y1 = z1**2 + x1 + z2 - 0.2*y2
    y2 = math.sqrt(y1) + z1 + z2

    # Write the output
    xml_safe_create_element(tree, '/dataSchema/analyses/y1', str(y1))

# Path: openlego/utils/xml_utils.py
# def xml_safe_create_element(
#         tree,       # type: etree._ElementTree
#         xpath,      # type: str
#         value=None  # type: Optional[Union[str, int, float, List[Union[str, int, float]], np.ndarray]]
# ):
#     # type: (...) -> etree._Element
#     """Create an element at the given XML XPath with the given value.
# 
#     This method ensures that all elements implied by the given X-Path exist.
# 
#     Supplying a value is optional. If no value is supplied an empty XML node is created at the deepest level implied by
#     the XPath.
# 
#     Parameters
#     ----------
#         tree : :obj:`etree._ElementTree`
#             `etree._ElementTree` in which to create the element.
# 
#         xpath : str
#             XPath to ensure.
# 
#         value : str or int or float or list of str or list of int or list of float or :obj:`np.ndarray`
#             Optional value to write at the deepest node of the ensured XPath.
# 
#     Returns
#     -------
#         :obj:`etree._Element`
#             Instance of `etree._Element` corresponding to the newly created element.
#     """
#     # Split the xpath to get the intermediate nodes as a list
#     xpath_list = xpath.split('/')
#     n = len(xpath_list)
# 
#     # Loop over the elements in the XPath from tip to root until the XPath is found to already exist
#     elem = None
#     i = 0
#     for i in range(0, n - 1):
#         xpath = '/'.join(xpath_list[0:(n - i)])
#         try:
#             elems = tree.xpath(xpath)
#             if len(elems):
#                 elem = elems[0]
#                 break
#         except etree.XPathError:
#             raise ValueError('Specified XPath {} is invalid.'.format(xpath))
# 
#     # If no existing element was found the root elements of the tree and XPath don't match
#     if elem is None:
#         raise ValueError("Specified XPath is incompatible with the given XML tree: root tags don't match")
# 
#     # Loop over the part of the XPath beyond this point and create all intermediate elements including attributes
#     for j in range(n - i, n):
#         tag = xpath_list[j]
# 
#         # See if this node has an integer index specified
#         match_ind = re_ind.search(tag)
#         if match_ind:
#             tag = tag[:match_ind.start()] + tag[match_ind.end():]
#             index = int(match_ind.group(1)) - 1
#         else:
#             index = 0
# 
#         # Find any attributes at this node
#         attrib = {}
#         match_attr = list(re_atr.finditer(tag))
#         if match_attr:
#             # Loop over all attributes on this node
#             for match in match_attr:
#                 if match.start() < len(tag):
#                     tag = tag[:match.start()]
#                 attrib.update({match.group(1): match.group(2)})
# 
#         # Check if there are siblings with the same name
#         siblings = elem.findall(tag)
#         n_siblings = len(siblings)
# 
#         # Check if there's a sibling with the same name at this index without conflicting attributes
#         if index < n_siblings and not any(
#                 [siblings[index].attrib[key] != attrib[key] for key in attrib.keys() if key in siblings[index].attrib]):
#             # If so, use it instead of adding a new one
#             siblings[index].attrib.update(attrib)
#             elem = siblings[index]
#         elif index <= n_siblings:
#             # In this case just append a new element
#             _elem = etree.Element(tag, attrib)
#             elem.append(_elem)
#             elem = _elem
#         else:
#             # In the last case, insert as many empty siblings until this node's index
#             sibling = None
#             for i in range(index - n_siblings):
#                 _sibling = etree.Element(tag)
#                 if i == 0:
#                     if not n_siblings:
#                         elem.append(_sibling)
#                     else:
#                         siblings[-1].addnext(_sibling)
#                 else:
#                     sibling.addnext(_sibling)
#                 sibling = _sibling
# 
#             # Finally at a new element at the right index with all attributes
#             elem = etree.Element(tag, attrib)
#             sibling.addnext(elem)
# 
#         # Finally we can update the current XPath, since it has been assured to exist at this point
#         xpath = '/'.join([xpath, xpath_list[j]])
# 
#     # If a value was supplied assign it to the deepest element in the XPath
#     if value is not None:
#         value_to_xml(elem, value)
# 
#     return elem


# Path: openlego/test_suite/test_examples/sellar_competences_virtual/sellar_code/d12.py
import math
import argparse
from lxml import etree
from openlego.utils.xml_utils import xml_safe_create_element

    y2 = sqrt(y1) + z1 + z2
    (one execution)

Call using:
    python d12.py input.xml output.xml

The script is written for Python 2.7!

Copyright 2019, DLR, Jasper Bussemaker.
Licence: MIT
"""


def run(input_xml_file, output_xml_file):
    # Load input file
    tree = etree.parse(input_xml_file)
    root = tree.getroot()

    # Load input parameters for this discipline
    x1 = float(root.find('./variables/x1').text)
    z1 = float(root.find('./variables/z1').text)
    z2 = float(root.find('./variables/z2').text)
    y2 = float(root.find('./analyses/y2').text)

    # "Run" the discipline calculations
    y1 = z1**2 + x1 + z2 - 0.2*y2
    y2 = math.sqrt(y1) + z1 + z2

    # Write the output
    xml_safe_create_element(tree, '/dataSchema/analyses/y1', str(y1))

    xml_safe_create_element(tree, '/dataSchema/analyses/y2', str(y2))