Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
CIMObjectHandler.cpp 101.60 KiB
#include <CIMExceptions.hpp>
#include "CIMObjectHandler.h"
#include "ModelicaWorkshop/ModPowerSystems/Connection.h"
/**\brief Macro for transformation.extent setting
 */
#define  SET_TRANS_EXTENT(component, type_str)                                                  \
                      component->annotation.placement.transformation.extent.first.x =            \
                      configManager.type_str##_parameters.annotation.transformation_extent[0];  \
                      component->annotation.placement.transformation.extent.first.y =            \
                      configManager.type_str##_parameters.annotation.transformation_extent[1];  \
                      component->annotation.placement.transformation.extent.second.x =           \
                      configManager.type_str##_parameters.annotation.transformation_extent[2];  \
                      component->annotation.placement.transformation.extent.second.y =           \
                      configManager.type_str##_parameters.annotation.transformation_extent[3];  \

/**\brief Macro for NEPLAN Voltage unit fix
 */
#define FIX_NEPLAN_VOLTAGE(component)                                                           \
                    if(this->configManager.us.voltage_unit == "V"){                             \
                    component->set_Vnom(component->Vnom());                                       \
                    } else if (this->configManager.us.voltage_unit == "kV") {                   \
                    component->set_Vnom(component->Vnom()*1000);                                  \
                    } else if(this->configManager.us.voltage_unit == "mV") {                    \
                    component->set_Vnom(component->Vnom()*0.001);                                 \
                    } else if(this->configManager.us.voltage_unit == "MV"){                     \
                    component->set_Vnom(component->Vnom()*1000000);                               \
                    }                                                                           \


/**
 * Constructor
 * rvalue reference
 */
CIMObjectHandler::CIMObjectHandler(std::vector<BaseClass *> &&CIMObjects)
        : _CIMObjects(CIMObjects) {

    _t_points.xPosition = 0;
    _t_points.yPosition = 0;
}

CIMObjectHandler::~CIMObjectHandler() {

    auto sv_it = svPowerFlowMap.begin();
    auto Opl_it = OpLimitMap.begin();
    auto svVolt_it = svVoltageMap.begin();
    auto used_it = _UsedObjects.begin();
    auto generator_it = generatorMap.begin();
    auto terminalList_it = terminalList.begin();
    auto SynMachineMap_it = SynMachineMap.begin();
    auto PiLineMap_it = PiLineMap.begin();

    while (used_it != _UsedObjects.end())
    {
        delete used_it->second;
        _UsedObjects.erase(used_it++);
    }
    while (generator_it != generatorMap.end())
    {
        generatorMap.erase(generator_it++);
    }

    while (sv_it != svPowerFlowMap.end())
    {
        svPowerFlowMap.erase(sv_it++);
    }

    while (svVolt_it != svVoltageMap.end())
    {
        svVoltageMap.erase(svVolt_it++);
    }

    while (Opl_it != OpLimitMap.end())
    {
        OpLimitMap.erase(Opl_it++);
    }
    while (terminalList_it != terminalList.end())
    {
        terminalList.erase(terminalList_it++);
    }
    while (SynMachineMap_it != SynMachineMap.end())
    {
        SynMachineMap.erase(SynMachineMap_it++);
    }
    while (PiLineMap_it != PiLineMap.end())
    {
        PiLineMap.erase(PiLineMap_it++);
    }
}

/**
 * Get all settings from config.cfg.
 */
void CIMObjectHandler::get_config(std::string templates) {

    template_folder = templates;
    print_separator();
    std::cout << "reading config files..." << std::endl;
    this->configManager.getAllSettings();
    std::cout << "using templates: " << templates <<"\n";
    configManager.template_folder = templates;
    this->configManager.getConnectionConfigFiles();
    this->configManager.getConnectionNames();
    Connection::setConfigManager(&this->configManager);
    print_separator();
}

/**
 * Print the object name or RTTI name
 */
void CIMObjectHandler::print_RTTI(BaseClass *Object) {

    std::cout << "The following CIM model is not used:" << std::endl;
    if (auto *io = dynamic_cast<IdentifiedObjectPtr>(Object)) {
        std::cout << "IdentifiedObject.name: " << io->name << std::endl;
    }
    const std::type_info &info = typeid(*Object);
    std::cout << "RTTI name: " << info.name() << std::endl;
    std::cout << std::endl;
}


/*
 * Funtion that removes non alphabetic or numeric characters and replaces them by their hex value
 * Terminal(1) will be converted to Terminal_xy_1_yx
 */
void CIMObjectHandler::remove_non_alnums(IdentifiedObjectPtr identified_obj){
    auto name = identified_obj->name;
    String new_name;
    for(auto el : name){
        if( !(std::isalnum(el) || el == '_' || el == '-')){
            char output[2];
            sprintf((char*)(output),"%02X", el);
            if(el == name[-1]){
                new_name = new_name + '_'+ output[0] + output[1];
            }else{
                new_name = new_name + '_'+ output[0] + output[1] + '_';
            }

        }else{
            new_name = new_name + el;
        }
    }
    identified_obj->name = new_name;
}

/**
 * Add mem address to object name to achieve unique naming
 */
void CIMObjectHandler::add_mem_address(IdentifiedObjectPtr identified_obj){
    std::stringstream ss;
    ss << static_cast<const void*>(identified_obj);
    std::string addrStr = ss.str();
    identified_obj->name = identified_obj->name + '_' + addrStr;
}

/**
 * frist searching loop
 * to find I_max of ACLineSegment, SvPowerFlow of Terminal for PQLoad
 * using hashmap
 */
bool CIMObjectHandler::pre_process() {
    ///pre searching loop
    std::list<TerminalPtr>::iterator terminal_it;
    std::list<ConductingPtr >::iterator conducting_it;
    for (BaseClass *Object : this->_CIMObjects) {

        if(auto identified_obj = dynamic_cast<IdentifiedObjectPtr >(Object)){
            this->remove_non_alnums(identified_obj);
            if(this->configManager.make_unique_names == true)
                this->add_mem_address(identified_obj);
        }
        if (this->configManager.gs.apply_Neplan_fix == true) {
            ///find OperationLimitSet for AClineSegment, stored in hashmap
            if (auto *op_limitset = dynamic_cast<OpLimitSetPtr>(Object)) {
                if (auto *ac_line = dynamic_cast<AcLinePtr>(op_limitset->Equipment)) {
                    OpLimitMap.insert({ac_line, op_limitset}); //hashmap
                }else{
                    for (BaseClass *Object1 : this->_CIMObjects) {
                        if(auto *terminal = dynamic_cast<TerminalPtr> (Object1)){
                            if(terminal->mRID == op_limitset->Terminal->mRID){
                                if (auto *ac_line = dynamic_cast<AcLinePtr>(terminal->ConductingEquipment)) {
                                    OpLimitMap.insert({ac_line, op_limitset});
                                    break;
                                }
                            }

                        }
                    }
                }
            }
        }
        if (this->configManager.svSettings.useSVforEnergyConsumer == true
            or this->configManager.svSettings.useSVforGeneratingUnit == true
            or this->configManager.svSettings.useSVforExternalNetworkInjection == true) {
            ///find terminal's svPowerFlow
            if (auto *sv_powerflow = dynamic_cast<SVPowerFlowPtr>(Object)) {
                svPowerFlowMap.insert({sv_powerflow->Terminal, sv_powerflow}); //hashmap
            } else if (auto *sv_voltage = dynamic_cast<SVVoltagePtr>(Object)) {
                svVoltageMap.insert({ (sv_voltage->TopologicalNode), sv_voltage});
            }
        }
        if (auto *generatingUnit = dynamic_cast<GeneratingUnitPtr > (Object)) {
            for (rotatingMachine_it = generatingUnit->RotatingMachine.begin();
                 rotatingMachine_it != generatingUnit->RotatingMachine.end();
                 ++rotatingMachine_it) {
                generatorMap.insert({(*rotatingMachine_it), generatingUnit});
            }
        }
        if (auto *base_voltage = dynamic_cast<BaseVoltagePtr >(Object)) {
            for( conducting_it = base_voltage->ConductingEquipment.begin();
                 conducting_it != base_voltage->ConductingEquipment.end();
                 conducting_it ++){
                baseVoltageMap.insert({*conducting_it, base_voltage});
            }
        }
        if(auto *syn_machine_dyn = dynamic_cast<SynMachineDynPtr> (Object)){
            SynMachineMap.insert({syn_machine_dyn->SynchronousMachine, syn_machine_dyn});
        }
        if (this->configManager.ss.use_TPNodes == true) {
            if (auto *tp_node = dynamic_cast<TPNodePtr>(Object)) {
                for (terminal_it = tp_node->Terminal.begin(); terminal_it != tp_node->Terminal.end(); ++terminal_it) {
                    terminalList[tp_node].push_back(*terminal_it);
                    if(auto *ac_line = dynamic_cast<AcLinePtr>((*terminal_it)->ConductingEquipment )){
                        PiLineMap[ac_line].push_back(*terminal_it);
                    }
                }
            }
        } else {
            if (auto *terminal = dynamic_cast<TerminalPtr>(Object)) {
                terminalList[terminal->ConnectivityNode].push_back(terminal);
                if(terminal->ConnectivityNode == nullptr)
                    std::cerr<< "Terminal " << terminal << " has no connectivity node connected. You might use the wrong topological model."
                             << " Verify that the use_TPNodes option is set correctly." << std::endl;
            }
        }

    }
    if(configManager.ignore_unconnected_components == true){
        remove_unconnected_components();
    }

    return true;
}


/**
 *  Function that removes all components that are not connected to a Slack,
 *  or in case that there is no Slack only creates the larges component
 */
void  CIMObjectHandler::remove_unconnected_components() {
    // TODO Code cleanup: create fct that returns tpNode of extNW
    // TODO Create fct that for a given start node returns a list of connected tpNodes
    // find external network tpNode
    std::vector<BaseClass *> tpNodeList;
    BaseClass *externalNW_TPNode = nullptr;
    std::unordered_map<BaseClass *, std::list<BaseClass *> > obj2TPNodeMap;

    // check if the connected property of terminals is initalized somewhere
    bool connected_terminal_exists = false;
    for (auto object_it = terminalList.begin(); object_it != terminalList.end(); object_it++) {
        BaseClass *tp_node = (*object_it).first;
        std::list<TerminalPtr> terminals = (*object_it).second;
        tpNodeList.push_back(tp_node);
        for (auto terminal : terminals) {
            try{
                bool connected = terminal->connected;
                if (connected == true){
                    obj2TPNodeMap[terminal->ConductingEquipment].push_back(tp_node);
                    connected_terminal_exists = true;
                }
                else{
                    std::cout << "the terminal is connected "<< terminal->name << std::endl;
                }
                if (auto *externalNetwork = dynamic_cast<ExNIPtr >((terminal)->ConductingEquipment)) {
                    externalNW_TPNode = tp_node;
                }
            }catch(ReadingUninitializedField* e){
                std::cout << "Uninitalized connected property for Terminal " << terminal->name << std::endl;
                continue;
            }

        }
    }
    if( connected_terminal_exists == false){
        std::cout << "There exists no terminal with the connected property set to true."
                " This might be due to uninitalized values. \n"
                  << "We change the ignore_unconnected_components option to false." << std::endl;
        this->configManager.ignore_unconnected_components = false;

        return;
    }

    // helper fct that for a given start node returns all connected nodes (the component)
    auto get_component = [this](std::unordered_map<BaseClass *, std::list<BaseClass *> > _obj2TPNodeMap,
                                BaseClass *_start_node){
        std::queue<BaseClass*> qq;
        qq.push(_start_node);
        BaseClass* currTPNode;
        std::vector<BaseClass* > component;
        while(!qq.empty()){
            currTPNode = qq.front();
            qq.pop();
            if(std::find(component.begin(), component.end(), currTPNode)
               != component.end())
                continue;
            else
                component.push_back(currTPNode);
            for(auto terminal : this->terminalList[currTPNode]){
                try{
                    bool connected = terminal->connected;

                    if(connected == true){
                        for(auto tp_node : _obj2TPNodeMap[terminal->ConductingEquipment]){
                            if (tp_node != currTPNode)
                                qq.push(tp_node);
                        }
                    }
                }catch(ReadingUninitializedField* e) {
                    std::cout << "Uninitalized connected property for Terminal " << terminal->name << std::endl;
                    continue;
                }
            }
        }
        return component;
    };

    // if there is no slack create largest connected component
    // otherwise create component connected to the slack
    std::vector<BaseClass*> component;
    if (externalNW_TPNode == nullptr){
        std::cerr << "The ignore_unconnected_components option in the options.cfg is set to true but there is no Slack in the given network. "
                "Creating the largest connected component." << std::endl;
        while(tpNodeList.size() > 0 ){
            auto curr_component = get_component(obj2TPNodeMap, *(tpNodeList.begin()));
            if(curr_component.size() > component.size()){
                std::cout << "found new largest compnent of size: " << curr_component.size()
                          <<" before "<<component.size() <<std::endl;
                component = curr_component;
            }
            for(auto el : curr_component){
                auto pos = std::find(tpNodeList.begin(), tpNodeList.end(), el);
                if(pos != tpNodeList.end())
                    tpNodeList.erase(pos);
            }
        }
    }else{
        component = get_component(obj2TPNodeMap, externalNW_TPNode);
    }

    // remove tpNodes that are not connected to external network
    std::vector<BaseClass * > removal_list;
    for(auto el : terminalList){
        if(std::find(component.begin(), component.end(), el.first) == component.end())
            removal_list.push_back(el.first);
    }
    for(auto el : removal_list){
        terminalList.erase(el);
    }

}


/**
 * Generate the modelica code
 * by parsering the _CIMObjects
 */
bool CIMObjectHandler::ModelicaCodeGenerator(std::string output_file_name, int verbose_flag) {
    const std::string filename = output_file_name;
    ctemplate::TemplateDictionary *dict = new ctemplate::TemplateDictionary("MODELICA");///set the main tpl file

    // TODO: Not sure if the dictionary should be changed to DISTAIX?
    // ctemplate::TemplateDictionary *dict;
    // if(this->configManager.gs.create_distaix_format == true) {
    //   dict = new ctemplate::TemplateDictionary("DISTAIX");///set the main tpl file for distaix format
    // } else {
    //   dict = new ctemplate::TemplateDictionary("MODELICA");///set the main tpl file for modelica format
    // }


    this->SystemSettingsHandler(filename, dict);

    ///first searching loop, to find I_max of ACLineSegment, SvPowerFlow of Terminal for PQLoad
    this->pre_process();
    std::unordered_map<BaseClass*, ModBaseClass*> copy;



    std::list<TerminalPtr>::iterator terminal_it;
    /// Each iteration takes one TopologicalNode creates a Busbar for it and creates and connects all objects
    /// that are connected to the TopologicalNode to the Busbar

    for(auto object_it = terminalList.begin(); object_it!= terminalList.end(); object_it++) {

        BaseClass * Object = (*object_it).first;
        std::list<TerminalPtr> terminals = (*object_it).second;

        if(this->configManager.ignore_unconnected_components == true){
            // in case there are no connected terminals attached to the busbar don't create it
            bool connected_terminal_exists = false;
            for(auto terminal : terminals)
                try {
                    bool connected = terminal->connected;
                    if(connected == true){
                        connected_terminal_exists = true;
                        break;
                    }
                }catch(ReadingUninitializedField* e) {
                    std::cout << "Uninitalized connected property for Terminal " << terminal->name << std::endl;
                    continue;
                }

            if(connected_terminal_exists == false){
                std::cout << "there exists no connected terminal!" << std::endl;
                continue;
            }


        }
        if(this->configManager.ss.use_TPNodes == true){//useTP == true
            auto *tp_node = dynamic_cast<TPNodePtr>(Object) ;
            this->currBusbar = this->TopologicalNodeHandler(tp_node, dict);

            if (this->configManager.household_parameters.use_households == true ) {
                this->HouseholdComponetsHandler(tp_node, dict);
            }
            this->currNode = tp_node;
        }else{
            if(auto *conn_node = dynamic_cast<ConnectivityNodePtr>(Object)){
                this->currBusbar = this->ConnectivityNodeHandler(conn_node, dict);

                if (this->configManager.household_parameters.use_households == true) {
                    this->HouseholdComponetsHandler(conn_node, dict);
                }
                this->currNode = conn_node;
            }else{
                std::cerr<< "The object is not a connectivity node. You might use the wrong topological model."
                         << " Verify that the use_TPNodes option is set correctly." << std::endl;

            }
        }
        BusBar* busbar = this->currBusbar;
        BaseClass* tp_node = this->currNode;
        // ignore terminals that are not connected

        // create all objects that are connected to the TopologicalNode and connect it to the BusBar
        for (TerminalPtr terminal : terminals ) {
            if(this->configManager.ignore_unconnected_components == true)
                if(terminal->connected == false)
                    continue;
            //ConnectivityNode no use for NEPLAN
            /*if (auto *connectivity_node = dynamic_cast<ConnectivityNodePtr>((*terminal_it)->ConnectivityNode)) {

              ConnectivityNode connectivity_Node = this->ConnectivityNodeHandler(tp_node, (*terminal_it),
                                                                                connectivity_node, dict);
              Connection conn(&busbar, &connectivity_Node);
              connectionQueue.push(conn);
            }*/

            if (auto *externalNI = dynamic_cast<ExNIPtr>((terminal)->ConductingEquipment)) {
                if(_UsedObjects.find(externalNI) != _UsedObjects.end()) {
                }else{
                    ModSlack* slack = this->ExternalNIHandler(tp_node, (terminal), externalNI, dict);
                    _UsedObjects.insert({externalNI, slack});
                }
                Connection conn(busbar, (ModSlack* )_UsedObjects[externalNI]);
                connectionQueue.push(conn);

            } else if (auto *power_trafo = dynamic_cast<PowerTrafoPtr>((terminal)->ConductingEquipment)) {
                if(_UsedObjects.find(power_trafo) != _UsedObjects.end()) {
                    ((ModTransformer* )_UsedObjects[power_trafo])->setBus(busbar);
                }else{
                    ModTransformer* trafo = this->PowerTransformerHandler(busbar, (terminal), power_trafo, dict);
                    _UsedObjects.insert({power_trafo, trafo});
                }
                Connection conn(busbar, (ModTransformer* )_UsedObjects[power_trafo]);
                connectionQueue.push(conn);

            } else if (auto *ac_line = dynamic_cast<AcLinePtr>((terminal)->ConductingEquipment)) {
                if(configManager.ignore_unconnected_components == true){
                    bool all_terminals_connected = true;
                    for(auto piTerminal : PiLineMap[ac_line]){
                        if(piTerminal->connected == false)
                            all_terminals_connected = false;
                    }
                    if(all_terminals_connected != true)
                        continue;
                }
                if(_UsedObjects.find(ac_line) != _UsedObjects.end()) {
                    ((ModPiLine* )_UsedObjects[ac_line])->setBus(busbar);
                }else {
                    if (template_folder == "DistAIX_templates") {
                        /* Changed implementation to enable creation of lossy cables for DistAIX format.
                        * Instead of creating "connections", the name of the busbar is stored when visited for the first time.
                        * When visiting the pi_line for the second time, the name of the current busbar, as well as the name of the busbbar
                        * stored during the first visit are passed as optional arguments to the ACLineSegmentHandler.
                        * This handler was modified in such a way, that those additional arguments are stores as dictionary values
                        * used in the DistAIX templates.
                        */

                        auto searchIt = piLineIdMap.find(ac_line);
                        if (searchIt != piLineIdMap.end()) {

                            ModPiLine* pi_line = this->ACLineSegmentHandler(tp_node, busbar, (terminal), ac_line, dict,
                                                                         piLineIdMap[ac_line], busbar->name());
                            _UsedObjects.insert({ac_line, pi_line});
                        } else {

                            piLineIdMap[ac_line] = busbar->name();

                        }
                    } else {

                        ModPiLine* pi_line = this->ACLineSegmentHandler(tp_node, busbar, (terminal), ac_line, dict);
                        _UsedObjects.insert({ac_line, pi_line});
                    }
                }
                Connection conn(busbar, ((ModPiLine*)_UsedObjects[ac_line]));
                connectionQueue.push(conn);
            } else if (auto *energy_consumer = dynamic_cast<EnergyConsumerPtr>((terminal)->ConductingEquipment)) {
                if(_UsedObjects.find(energy_consumer) != _UsedObjects.end()) {

                }else {

                    if (this->configManager.household_parameters.use_households == false) {
                        ModPQLoad* pqload = this->EnergyConsumerHandler(tp_node,(terminal), energy_consumer, dict);
                        _UsedObjects.insert({energy_consumer, pqload});
                    }
                }
                Connection conn(busbar, (ModPQLoad*)_UsedObjects[energy_consumer]);
                connectionQueue.push(conn);
            } else if (auto *synchronous_machine = dynamic_cast<SynMachinePtr >((terminal)->ConductingEquipment)) {
                if(_UsedObjects.find(synchronous_machine) != _UsedObjects.end()) {

                }else {
                    if(SynMachineMap.find(synchronous_machine) != SynMachineMap.end()){
                        SynMachineDyn *synMachineDyn = this->synMachineDynHandler(tp_node, terminal,
                                                                                  SynMachineMap[synchronous_machine], dict);
                        _UsedObjects.insert({synchronous_machine, synMachineDyn});

                    }else{
                        if (this->configManager.household_parameters.use_households == false) {
                            ModPVNode * pv_node = this->SynchronousMachineHandlerType0(tp_node, (terminal),
                                                                                    synchronous_machine, dict);
                            _UsedObjects.insert({synchronous_machine,pv_node});

                        }
                    }
                }
                std::cout << "push to connection qq " << busbar->name() << " "
                          << ((ModPVNode* )_UsedObjects[synchronous_machine])->name()<< std::endl;
                Connection conn(busbar, (ModPVNode* )_UsedObjects[synchronous_machine]);
                connectionQueue.push(conn);

                // THIS IS WRONG SYNMACHINEDYNAMICS IS NO CONDUCTING EQUIPMENT
                // TODO ADD THE CONNECTION CONSTRUCTOR
                // Connection conn(busbar, (SynMachineDyn *) _UsedObjects[synchronous_machine]);
                // connectionQueue.push(conn);
            }else if (auto *cim_breaker = dynamic_cast<BreakerPtr> ((terminal)->ConductingEquipment)){
                if(_UsedObjects.find(cim_breaker) != _UsedObjects.end()) {
                    ModBreaker* someBreaker = ((ModBreaker* )_UsedObjects[cim_breaker]);
                    someBreaker->setBus(busbar);
                }
                else{
                    ModBreaker * breaker = this->BreakerHandler(busbar,(terminal), cim_breaker , dict);
                    _UsedObjects.insert({cim_breaker, breaker});
                }
                Connection conn(busbar, (ModBreaker* )_UsedObjects[cim_breaker]);
                connectionQueue.push(conn);

            }
#ifdef SINERGIEN
                else if (auto *battery_storage = dynamic_cast<BatteryStoragePtr>((*terminal_it)->ConductingEquipment)){
            Battery battery = this->BatteryStorageHandler(tp_node, (*terminal_it), battery_storage, dict);
            Connection conn(&busbar, &battery);
            connectionQueue.push(conn);

        }
#endif
            else {

                if(verbose_flag == 1) {
                    print_RTTI((*terminal_it)->ConductingEquipment); /// In verbose module to show the no used object information
                }
            }
        }
        if (this->configManager.household_parameters.use_households == true ) {

            while (!this->householdQueue.empty()) {

                switch (this->householdQueue.front().HouseholdType()) {
                    case (HouseholdType::Type1):
                        if (this->householdQueue.front().sequenceNumber() == 0
                            || this->householdQueue.front().sequenceNumber() == 1) {
                            ctemplate::TemplateDictionary *household_dict = dict->AddIncludeDictionary(
                                    "HOUSEHOLD_TYPE1_DICT");
                            household_dict->SetFilename(
                                    this->configManager.ts.directory_path + "resource/" + template_folder + "/HouseholdType1.tpl");
                            this->householdQueue.front().set_template_values(household_dict);
                        }
                        break;
                    case (HouseholdType::Type2):
                        if (this->householdQueue.front().sequenceNumber() == 0
                            || this->householdQueue.front().sequenceNumber() == 1) {
                            ctemplate::TemplateDictionary *household_dict = dict->AddIncludeDictionary(
                                    "HOUSEHOLD_TYPE2_DICT");
                            household_dict->SetFilename(
                                    this->configManager.ts.directory_path + "resource/" + template_folder + "/HouseholdType2.tpl");
                            this->householdQueue.front().set_template_values(household_dict);
                        }
                        break;
                    default:break;
                }
                Connection conn(busbar, &this->householdQueue.front());
                connectionQueue.push(conn);

                this->householdQueue.pop();
            }
            while (!this->pqloadQueue.empty()) {
                if (this->configManager.pqload_parameters.type == 1 && pqloadQueue.front().PQLoadType() == PQLoadType::Standard) {
                    ctemplate::TemplateDictionary *pqLoad_dict = dict->AddIncludeDictionary("PQLOAD_DICT");
                    pqLoad_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PQLoad.tpl");
                    pqloadQueue.front().set_template_values(pqLoad_dict);
                } else if (this->configManager.pqload_parameters.type == 2 && pqloadQueue.front().PQLoadType() == PQLoadType::Profile) {
                    ctemplate::TemplateDictionary *pqLoad_dict = dict->AddIncludeDictionary("PQLOAD_PROFILE_DICT");
                    pqLoad_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PQLoadProfile.tpl");
                    pqloadQueue.front().set_template_values(pqLoad_dict);
                } else if(this->configManager.pqload_parameters.type == 3 && pqloadQueue.front().PQLoadType() == PQLoadType::NormProfile){
                    ctemplate::TemplateDictionary *pqLoad_dict = dict->AddIncludeDictionary("PQLOAD_NORM_PROFILE_DICT");
                    pqLoad_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PQLoadNormProfile.tpl");
                    pqloadQueue.front().set_template_values(pqLoad_dict);
                }
                Connection conn(busbar, &pqloadQueue.front());
                connectionQueue.push(conn);
                pqloadQueue.pop();
            }
            while (!this->solarGeneratorQueue.empty()) {

                ctemplate::TemplateDictionary *solar_generator_dict = dict->AddIncludeDictionary(
                        "SOLARGENERATOR_DICT");
                solar_generator_dict->SetFilename(
                        this->configManager.ts.directory_path + "resource/" + template_folder + "/SolarGenerator.tpl");
                solarGeneratorQueue.front().set_template_values(solar_generator_dict);
                Connection conn(busbar, &solarGeneratorQueue.front());
                connectionQueue.push(conn);
                solarGeneratorQueue.pop();
            }
            while (!this->pvNodeQueue.empty()) {

                ctemplate::TemplateDictionary *pv_node_dict = dict->AddIncludeDictionary(
                        "PVNODE_DICT");
                pv_node_dict->SetFilename(
                        this->configManager.ts.directory_path + "resource/" + template_folder + "/PVNode.tpl");
                pvNodeQueue.front().set_template_values(pv_node_dict);
                Connection conn(busbar, &pvNodeQueue.front());
                connectionQueue.push(conn);
                pvNodeQueue.pop();
            }
        }
    }

    this->ConnectionHandler(dict);

    std::string modelica_output;

    if(template_folder == "DistAIX_templates") {
        this->configManager.gs.create_distaix_format = true;
        ctemplate::ExpandTemplate(this->configManager.ts.directory_path + "resource/" + template_folder + "/distaix.tpl",
                                  ctemplate::STRIP_BLANK_LINES, dict, &modelica_output);
    } else {
        ctemplate::ExpandTemplate(this->configManager.ts.directory_path + "resource/" + template_folder + "/modelica.tpl",
                                  ctemplate::STRIP_BLANK_LINES, dict, &modelica_output);
    }

#ifdef DEBUG
    #pragma message("DEBUG model activated!")
  std::cout << modelica_output;
#endif
    std::cout << this->configManager.fs.output_path << std::endl;
    // Write to file
    std::ofstream file;
    file.open(this->configManager.fs.output_path + filename + ".mo", std::fstream::trunc);
    if (file.good())
        file << modelica_output;
    file.close();
    modelica_output.clear();

    return true;
}

/**
 * TopologicalNode
 * Convert to busbar in Modelica
 */
bool CIMObjectHandler::SystemSettingsHandler(const std::string filename, ctemplate::TemplateDictionary *dict) {
    //Modelica_Header
    dict->AddSectionDictionary("HEADER_FOOTER_SECTION");
    dict->SetValue("GRID_NAME", filename);
    //Global Settings
    dict->AddSectionDictionary("SYSTEM_SETTINGS_SECTION");

    if (configManager.ss.enable) {
        auto *system = new ModPowerSystems::System(configManager);
        std::cout << "Using SystemSetting parameters from configuration!" << std::endl;
        system->set_template_values(dict);
        delete system;
    } else {
        auto *system = new ModPowerSystems::System(0, 0, 400, -400);
        system->set_name(filename);
        system->set_template_values(dict);
        delete system;
    }

    return true;
}

/**
 * TopologicalNode
 * Convert to busbar in Modelica
 */
BusBar* CIMObjectHandler::TopologicalNodeHandler(const TPNodePtr tp_node, ctemplate::TemplateDictionary *dict) {
    BusBar* busbar = new BusBar();
    busbar->set_name(name_in_modelica(tp_node->name));
    busbar->annotation.placement.visible = true;
    busbar->set_Vnom(tp_node->BaseVoltage->nominalVoltage.value);

    if(this->configManager.us.enable){
        FIX_NEPLAN_VOLTAGE(busbar);
    }

    if (this->configManager.busbar_parameters.enable) {
        SET_TRANS_EXTENT(busbar,busbar);//Macro
        busbar->annotation.placement.visible = configManager.busbar_parameters.annotation.visible;
    }
    busbar->set_Vnom_displayUnit(busbar->Vnom_displayUnit());
    // std::list<DiagramObjectPtr>::iterator diagram_it is class member!
    int counter = 0;
    float currX = 0;
    float currY = 0;
    if (tp_node->DiagramObjects.begin() == tp_node->DiagramObjects.end()){
        std::cerr << "Missing Diagram Object for TpNode:  " << tp_node->name << " Taking average Terminal Position \n";

        for(std::list<TerminalPtr >::iterator terminal_it = tp_node->Terminal.begin();
            terminal_it != tp_node->Terminal.end(); terminal_it++) {
            if ((*terminal_it)->DiagramObjects.begin() != (*terminal_it)->DiagramObjects.end()) {

                for(diagram_it = (*terminal_it)->DiagramObjects.begin();
                    diagram_it!=(*terminal_it)->DiagramObjects.end(); ++diagram_it){
                    _t_points = this->calculate_average_position();
                    currX += _t_points.xPosition;
                    currY += _t_points.yPosition;
                    counter += 1;
                }

            }
        }
        if(counter == 0){
            busbar->annotation.placement.transformation.origin.x = 0;
            busbar->annotation.placement.transformation.origin.y = 0;

        }else{
            busbar->annotation.placement.transformation.origin.x = currX / counter;
            busbar->annotation.placement.transformation.origin.y = currY / counter;
        }
        busbar->annotation.placement.transformation.rotation = 0;
        ctemplate::TemplateDictionary *busbar_dict = dict->AddIncludeDictionary("BUSBAR_DICT");
        busbar_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/BusBar.tpl");
        busbar->set_template_values(busbar_dict);

    }else {
        for (diagram_it = tp_node->DiagramObjects.begin(); diagram_it != tp_node->DiagramObjects.end(); ++diagram_it) {
            _t_points = this->calculate_average_position();
            currX += _t_points.xPosition;
            currY += _t_points.yPosition;
            counter += 1;
            try{
                busbar->annotation.placement.transformation.rotation = (*diagram_it)->rotation.value;
            }catch(ReadingUninitializedField* e){
                busbar->annotation.placement.transformation.rotation = 0;
                std::cerr <<"Missing rotation for diagram obj"<< std::endl;

            }

        }
        busbar->annotation.placement.transformation.origin.x = currX / counter;
        busbar->annotation.placement.transformation.origin.y = currY / counter;
        ctemplate::TemplateDictionary *busbar_dict = dict->AddIncludeDictionary("BUSBAR_DICT");
        busbar_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/BusBar.tpl");
        busbar->set_template_values(busbar_dict);


        //BusBarSection used in Cimphony
//  std::list<TerminalPtr>::iterator terminal_it;
//  for (terminal_it = tp_node->Terminal.begin(); terminal_it!=tp_node->Terminal.end(); ++terminal_it) {
//    if (auto *busbar_section = dynamic_cast<BusBarSectionPtr>((*terminal_it)->ConductingEquipment)) {
//      this->BusBarSectionHandler(busbar_section, busbar, dict);
//    }
//  }
    }
    return busbar;
}


/**
 * Create a Busbar for the respective ConnectivityNode
 */
BusBar* CIMObjectHandler::ConnectivityNodeHandler(const ConnectivityNodePtr con_node, ctemplate::TemplateDictionary *dict) {
    BusBar* busbar = new BusBar();
    busbar->set_name(name_in_modelica(con_node->name));
    busbar->annotation.placement.visible = true;
    bool is_set = false;

    // ConnectivityNodes don't have a BaseVoltage in CIM. Therefore, we use the BaseVoltage
    // of the first ConductingEquipment found which is connected to the ConnectivityNode
    // If there is no ConductingEquipment with BaseVoltage connected we print an error
    // and use a default BaseVoltage
    std::list<TerminalPtr>::iterator terminal_it = terminalList[con_node].begin();
    while (is_set == false){
        if(baseVoltageMap.find((*terminal_it)->ConductingEquipment) != baseVoltageMap.end()){
            busbar->set_Vnom(baseVoltageMap[(*terminal_it)->ConductingEquipment]->nominalVoltage.value);
            is_set = true;
        }
        terminal_it ++;
        if(terminal_it == terminalList[con_node].end()){
            std::cerr << "No BaseVoltage connected to ConnectivityNode " << con_node->name << " using default value from cfg" <<std::endl;
            busbar->set_Vnom(this->configManager.default_baseKV);
            break;
        }
    }
    if(this->configManager.us.enable){
        FIX_NEPLAN_VOLTAGE(busbar);
    }

    if (this->configManager.busbar_parameters.enable) {
        SET_TRANS_EXTENT(busbar,busbar);//Macro
        busbar->annotation.placement.visible = configManager.busbar_parameters.annotation.visible;
    }
    busbar->set_Vnom_displayUnit(busbar->Vnom_displayUnit());
    // std::list<DiagramObjectPtr>::iterator diagram_it is class member!
    int counter = 0;
    float currX = 0;
    float currY = 0;

    std::cerr << "Connectivity Node has no Diagram Object:  " << con_node->name << " Taking average Terminal Position \n";

    for(std::list<TerminalPtr >::iterator terminal_it = terminalList[con_node].begin();
        terminal_it != terminalList[con_node].end(); terminal_it++) {
        if ((*terminal_it)->DiagramObjects.begin() != (*terminal_it)->DiagramObjects.end()) {

            for(diagram_it = (*terminal_it)->DiagramObjects.begin();
                diagram_it!=(*terminal_it)->DiagramObjects.end(); ++diagram_it){
                _t_points = this->calculate_average_position();
                currX += _t_points.xPosition;
                currY += _t_points.yPosition;
                counter += 1;
            }

        }
    }
    if(counter == 0){
        busbar->annotation.placement.transformation.origin.x = 0;
        busbar->annotation.placement.transformation.origin.y = 0;

    }else{
        busbar->annotation.placement.transformation.origin.x = currX / counter;
        busbar->annotation.placement.transformation.origin.y = currY / counter;
    }
    busbar->annotation.placement.transformation.rotation = 0;
    ctemplate::TemplateDictionary *busbar_dict = dict->AddIncludeDictionary("BUSBAR_DICT");
    busbar_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/BusBar.tpl");
    busbar->set_template_values(busbar_dict);

    return busbar;
}

/**
 * In the TopologicalNode to
 * find PQLoad in type1
 * find PQLoad, SolarGenerator, Battery which form HouseHold type2
 */
bool CIMObjectHandler::HouseholdComponetsHandler(BaseClass* tp_node, ctemplate::TemplateDictionary *dict) {

    std::list<TerminalPtr>::iterator terminal_it;
    if(this->configManager.household_parameters.type == "type1" ){

        for (terminal_it = terminalList[tp_node].begin(); terminal_it != terminalList[tp_node].end(); ++terminal_it) {

            if (auto *energy_consumer = dynamic_cast<EnergyConsumerPtr>((*terminal_it)->ConductingEquipment)) {

                ModPQLoad* pqload = this->EnergyConsumerHandler(tp_node, (*terminal_it), energy_consumer, dict);
                ModHousehold* household = new ModHousehold(*pqload);
                if (this->configManager.household_parameters.enable) {
                    SET_TRANS_EXTENT(household,household);
                    household->annotation.placement.visible = configManager.household_parameters.annotation.visible;
                }

                this->householdQueue.push(*household);
            }
        }
    } else if (this->configManager.household_parameters.type == "type2"){
        for (terminal_it = terminalList[tp_node].begin(); terminal_it != terminalList[tp_node].end(); ++terminal_it) {

            if (auto *energy_consumer = dynamic_cast<EnergyConsumerPtr>((*terminal_it)->ConductingEquipment)) {
                ModPQLoad* pqload = this->EnergyConsumerHandler(tp_node, (*terminal_it), energy_consumer, dict);
                this->pqloadQueue.push(*pqload);
            }else if (auto *synchronous_machine = dynamic_cast<SynMachinePtr >((*terminal_it)->ConductingEquipment)) {

                if (this->configManager.household_parameters.use_households == false) {
                    ModPVNode* pv_node = this->SynchronousMachineHandlerType0(tp_node, (*terminal_it),
                                                                           synchronous_machine, dict);
                    this->pvNodeQueue.push(*pv_node);

                }


            }

            if (this->pqloadQueue.size()==1 && this->solarGeneratorQueue.size()==1) {

                ModHousehold* household = new ModHousehold(this->pqloadQueue.front(), this->solarGeneratorQueue.front());  //type2

                if (this->configManager.household_parameters.enable) {
                    SET_TRANS_EXTENT(household,household);
                    household->annotation.placement.visible = configManager.household_parameters.annotation.visible;
                }

                this->householdQueue.push(*household);
                this->pqloadQueue.pop();
                this->solarGeneratorQueue.pop();
            }
        }
    }
    return !this->householdQueue.empty();
}

/**
 * compensate for busbar in Modelica
 * used in Cimphony
 */
bool CIMObjectHandler::BusBarSectionHandler(const BusBarSectionPtr busbar_section, BusBar &busbar,
                                            ctemplate::TemplateDictionary *dict) {

    if(busbar_section->DiagramObjects.begin() == busbar_section->DiagramObjects.end()){
        std::cerr << "Missing Diagram Object for Bus: " << busbar_section->name << " Default Position 0,0 \n";
        busbar.annotation.placement.transformation.origin.x = 0;
        busbar.annotation.placement.transformation.origin.y = 0;
        busbar.annotation.placement.transformation.rotation = 0;

        ctemplate::TemplateDictionary *busbar_dict = dict->AddIncludeDictionary("BUSBAR_DICT");
        busbar_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/BusBar.tpl");
        busbar.set_template_values(busbar_dict);
    }else{

        int counter = 0;
        float currX = 0;
        float currY = 0;
        for (diagram_it = busbar_section->DiagramObjects.begin();
             diagram_it!=busbar_section->DiagramObjects.end();
             ++diagram_it) {
            _t_points = this->calculate_average_position();
            currX += _t_points.xPosition;
            currY += _t_points.yPosition;
            counter += 1;
            busbar.annotation.placement.transformation.rotation = (*diagram_it)->rotation.value;
        }
        busbar.annotation.placement.transformation.origin.x = currX / counter;
        busbar.annotation.placement.transformation.origin.y = currY / counter;

        busbar.annotation.placement.transformation.origin.x = _t_points.xPosition;
        busbar.annotation.placement.transformation.origin.y = _t_points.yPosition;
        busbar.annotation.placement.transformation.rotation = (*diagram_it)->rotation.value;

        ctemplate::TemplateDictionary *busbar_dict = dict->AddIncludeDictionary("BUSBAR_DICT");
        busbar_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/BusBar.tpl");
        busbar.set_template_values(busbar_dict);
    }
    return true;
}

/**
 * ConnectivityNode
 * Convert to ConnectivityNode in Modelica
 *//*
ConnectivityNode CIMObjectHandler::ConnectivityNodeHandler(const TPNodePtr tp_node, const TerminalPtr terminal,
                                                          const ConnectivityNodePtr connectivity_node,
                                                          ctemplate::TemplateDictionary *dict) {
  ConnectivityNode conn_node;
  conn_node.set_Vnom(tp_node->BaseVoltage->nominalVoltage.value);
  if(this->configManager.us.enable){
    FIX_NEPLAN_VOLTAGE(conn_node);
  }
  conn_node.set_name(name_in_modelica(connectivity_node->name));
  conn_node.annotation.placement.visible = true;
  conn_node.set_sequenceNumber(terminal->sequenceNumber);
  conn_node.set_connected(terminal->connected);

  if(connectivity_node->DiagramObjects.begin() == connectivity_node->DiagramObjects.end()){
      std::cerr << "Missing Diagram Object for Connectivity Node: " << connectivity_node->name << " Default Position 0,0 \n";
      conn_node.annotation.placement.transformation.origin.x = 0;
      conn_node.annotation.placement.transformation.origin.y = 0;
      conn_node.annotation.placement.transformation.rotation = 0;

      if (conn_node.sequenceNumber()==0 || conn_node.sequenceNumber()==1) {
          ctemplate::TemplateDictionary *conn_node_dict = dict->AddIncludeDictionary("CONNECTIVITYNODE_DICT");
          conn_node_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/ConnectivityNode.tpl");
          conn_node.set_template_values(conn_node_dict);
      }
  }
  for (diagram_it = connectivity_node->DiagramObjects.begin();
       diagram_it!=connectivity_node->DiagramObjects.end();
       ++diagram_it) {
    _t_points = this->calculate_average_position();
    conn_node.annotation.placement.transformation.origin.x = _t_points.xPosition;
    conn_node.annotation.placement.transformation.origin.y = _t_points.yPosition;
    conn_node.annotation.placement.transformation.rotation = (*diagram_it)->rotation.value - 90;

    if (conn_node.sequenceNumber()==0 || conn_node.sequenceNumber()==1) {
      ctemplate::TemplateDictionary *conn_node_dict = dict->AddIncludeDictionary("CONNECTIVITYNODE_DICT");
      conn_node_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/ConnectivityNode.tpl");
      conn_node.set_template_values(conn_node_dict);
    }
  }

  return conn_node;
}
*/
/**
 * ConductingEquipment of Terminal
 * ConductingEquipment cast to ExternalNetworkInjection
 * Convert to slack in Modelica
 */
ModSlack* CIMObjectHandler::ExternalNIHandler(BaseClass* tp_node, const TerminalPtr terminal, const ExNIPtr externalNI,
                                           ctemplate::TemplateDictionary *dict) {
    ModSlack* slack = new ModSlack();

    slack->set_name(name_in_modelica(externalNI->name));
    try{
        slack->set_sequenceNumber(terminal->sequenceNumber);
    }catch(ReadingUninitializedField* e){
        slack->set_sequenceNumber(0);
        std::cerr <<"Missing sequence number in terminal sequence number " << terminal->name << std::endl;
    }
    slack->set_sequenceNumber(terminal->sequenceNumber);
    try{
        slack->set_connected(terminal->connected);
    }catch(ReadingUninitializedField* e){
        slack->set_connected(1);
        std::cerr <<"Missing connected property for terminal  " << terminal->name << std::endl;
    }
    slack->annotation.placement.visible = true;
    if (baseVoltageMap.find(externalNI) != baseVoltageMap.end()){
        slack->set_Vnom(baseVoltageMap[externalNI]->nominalVoltage.value);
    }else{
        slack->set_Vnom(((TPNodePtr)tp_node)->BaseVoltage->nominalVoltage.value);
        std::cerr <<"No BaseVoltage for ExternalNetworkInjection taking TPNode Voltage: " << std::endl;
    }



    if(this->configManager.svSettings.useSVforExternalNetworkInjection == true &&
       this->configManager.ss.use_TPNodes== true){
        slack->set_phiV(svVoltageMap[tp_node]->angle.value);
    }


    if(this->configManager.us.enable){
        FIX_NEPLAN_VOLTAGE(slack);
    }

    if (this->configManager.slack_parameters.enable) {
        SET_TRANS_EXTENT(slack,slack);
        slack->annotation.placement.visible = configManager.slack_parameters.annotation.visible;
    }
    if (externalNI->DiagramObjects.begin() == externalNI->DiagramObjects.end()){
        std::cerr << "Missing Diagram Object for ExternalNIHandler: " << externalNI->name << " Default Position 0,0 \n";
        slack->annotation.placement.transformation.origin.x = 0;
        slack->annotation.placement.transformation.origin.y = 0;
        slack->annotation.placement.transformation.rotation = 0;

        ctemplate::TemplateDictionary *slack_dict = dict->AddIncludeDictionary("SLACK_DICT");
        slack_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/Slack.tpl");
        slack->set_template_values(slack_dict);
    }else{
        int counter = 0;
        float currX = 0;
        float currY = 0;

        for (diagram_it = externalNI->DiagramObjects.begin(); diagram_it!=externalNI->DiagramObjects.end(); ++diagram_it) {
            _t_points = this->calculate_average_position();
            currX += _t_points.xPosition;
            currY += _t_points.yPosition;
            counter += 1;
        }
        slack->annotation.placement.transformation.origin.x = currX / counter;
        slack->annotation.placement.transformation.origin.y = currY / counter;


        ctemplate::TemplateDictionary *slack_dict = dict->AddIncludeDictionary("SLACK_DICT");
        slack_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/Slack.tpl");
        slack->set_template_values(slack_dict);
    }

    return slack;
}

/**
 * ConductingEquipment of Terminal
 * ConductingEquipment cast to ACLineSegment
 * Convert to Pi_line in Modelica
 */
ModPiLine *
CIMObjectHandler::ACLineSegmentHandler(BaseClass* tp_node, BusBar* busbar, const TerminalPtr terminal, const AcLinePtr ac_line,
                                       ctemplate::TemplateDictionary *dict, std::string node1Name /* = "" */, std::string node2Name /* = "" */) {

    ModPiLine * piline = new ModPiLine();
    piline->set_name(name_in_modelica(ac_line->name));
    float length = ac_line->length.value;
    // CIM unit length should be km but some files may have there lengths in m
    if(this->configManager.us.length_unit == "m"){
        length = length / 1000;
    }else if(this->configManager.us.length_unit == "km"){
    }

    piline->set_length(length);


    try{
        piline->set_r(ac_line->r.value/length);
    }catch(ReadingUninitializedField* e){
        piline->set_length(length);
        std::cerr<<"Missing r value" << std::endl;
    }


    try{
        piline->set_x(ac_line->x.value/length);
    }catch(ReadingUninitializedField* e){
        piline->set_x(length);
        std::cerr<<"Missing x value" << std::endl;
    }

    try{
        piline->set_b(ac_line->bch.value/length);
    }catch(ReadingUninitializedField* e){
        piline->set_b(length);
        std::cerr<<"Missing bch value" << std::endl;
    }


    try{
        piline->set_g(ac_line->gch.value);///ac_line->length.value);
    }catch(ReadingUninitializedField* e){
        piline->set_g(0);
        std::cerr<<"Missing gch value" << std::endl;
    }
    try{
        if(terminal->sequenceNumber == 2) {
            piline->setBus2(busbar);
        }else{
            piline->setBus1(busbar);
        }
    }catch(ReadingUninitializedField* e){
        piline->setBus1(busbar);
        std::cerr<<"Missing terminal seqNR" << std::endl;
    }

    if(configManager.add_Vnom_to_PiLine == true && configManager.ss.use_TPNodes == true){
        try{
            double vnom = ((TPNodePtr)tp_node)->BaseVoltage->nominalVoltage.value;
            if(this->configManager.us.enable) {
                if (this->configManager.us.voltage_unit == "V") {
                    piline->set_Vnom(vnom);
                } else if (this->configManager.us.voltage_unit == "kV") {
                    piline->set_Vnom(vnom * 1000);
                } else if (this->configManager.us.voltage_unit == "mV") {
                    piline->set_Vnom(vnom * 0.001);
                } else if (this->configManager.us.voltage_unit == "MV") {
                    piline->set_Vnom(vnom * 1000000);
                }
                // TODO SET DISPLAY UNIT
            }else{
                piline->set_Vnom(vnom);
            }

            //std::cout <<"Adding TPNode Voltage to PiLine: " << piline->name() << std::endl;
        }catch(ReadingUninitializedField* e){
            piline->set_Vnom(-1); // TODO find default value
            std::cerr<<"No Base Voltage at corresponding TPNode for PiLine setting to default value " << piline->name() << std::endl;
        }
    }else{
        piline->set_Vnom(-1);
    }



    if (this->configManager.gs.create_distaix_format == true && !node1Name.empty() && !node2Name.empty()) {
        piline->set_node1(node1Name);
        piline->set_node2(node2Name);
    }

    //find I_Max
    if(OpLimitMap[ac_line]){
        for(OpLimitPtr op_limit: OpLimitMap[ac_line]->OperationalLimitValue){
            if(auto current_limit = dynamic_cast<CurrentLimitPtr>(op_limit)){
                //if(current_limit->name == "Normal")
                piline->set_Imax(current_limit->value.value);
                /*else{
                    std::cout << "name of Current Limit is not Normal "<<piline->name() << std::endl;
                }*/
            }else{
                std::cout << "missing current Limit for PiLine "<<piline->name() << std::endl;
            }
        }
    }
    if(this->configManager.us.enable){
        if(this->configManager.us.current_unit == "A"){
            piline->set_Imax(piline->Imax());
        } else if(this->configManager.us.current_unit == "kA"){
            piline->set_Imax(piline->Imax()*1000);
        } else if(this->configManager.us.current_unit == "mA"){
            piline->set_Imax(piline->Imax()*0.001);
        } else if(this->configManager.us.current_unit == "MA"){
            piline->set_Imax(piline->Imax()*1000000);
        }
    }


    try{
        piline->set_connected(terminal->connected);
    }catch(ReadingUninitializedField* e){
        piline->set_connected(1);
        std::cerr<<"Missing connection info in terminal" << terminal << std::endl;
    }
    piline->annotation.placement.visible = true;

    if (this->configManager.piline_parameters.enable) {

        SET_TRANS_EXTENT(piline,piline);
        piline->annotation.placement.visible = configManager.piline_parameters.annotation.visible;
    }

    if (ac_line->DiagramObjects.begin() == ac_line->DiagramObjects.end()){
        std::cerr << "Missing Diagram Object for acLine: " << ac_line->name << " Default Position 0,0 \n";
        piline->annotation.placement.transformation.origin.x = 0;
        piline->annotation.placement.transformation.origin.y = 0;
        piline->annotation.placement.transformation.rotation = 0;

        ctemplate::TemplateDictionary *piLine_dict = dict->AddIncludeDictionary("PILINE_DICT");
        piLine_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PiLine.tpl");
        if(configManager.add_Vnom_to_PiLine == true) {
            piLine_dict->AddSectionDictionary("PILINE_VNOM");
        }
        piline->set_template_values(piLine_dict);
    }else {
        int counter = 0;
        float currX = 0;
        float currY = 0;
        for (diagram_it = ac_line->DiagramObjects.begin(); diagram_it != ac_line->DiagramObjects.end(); ++diagram_it) {
            _t_points = this->calculate_average_position();
            currX += _t_points.xPosition;
            currY += _t_points.yPosition;
            counter += 1;
            try{
                piline->annotation.placement.transformation.rotation = (*diagram_it)->rotation.value - 90;
            }catch(ReadingUninitializedField* e){
                piline->annotation.placement.transformation.rotation = 0;
                std::cerr <<"Missing rotation for diagram object" << piline->name() << std::endl;
            }
        }
        piline->annotation.placement.transformation.origin.x = currX/counter;
        piline->annotation.placement.transformation.origin.y = currY/counter;

        ctemplate::TemplateDictionary *piLine_dict = dict->AddIncludeDictionary("PILINE_DICT");
        piLine_dict->SetFilename(
                this->configManager.ts.directory_path + "resource/" + template_folder + "/PiLine.tpl");
        if(configManager.add_Vnom_to_PiLine == true) {
            piLine_dict->AddSectionDictionary("PILINE_VNOM");
        }
        piline->set_template_values(piLine_dict);

    }
    return piline;
}

/**
 * ConductingEquipment of Terminal
 * ConductingEquipment cast to PowerTransformer
 * Convert to Transformer in Modelica
 */
ModTransformer* CIMObjectHandler::PowerTransformerHandler(BusBar* busbar, const TerminalPtr terminal,
                                                       const PowerTrafoPtr power_trafo,
                                                       ctemplate::TemplateDictionary *dict) {

    ModTransformer* trafo = new ModTransformer();
    trafo->set_name(name_in_modelica(power_trafo->name));
    try{
        if(terminal->sequenceNumber == 2) {
            trafo->setBus2(busbar);
        }else{
            trafo->setBus1(busbar);
        }
    }catch(ReadingUninitializedField* e){
        trafo->setBus1(busbar);
        std::cerr <<"Missing sequence number in terminal sequence number " << terminal->name << std::endl;
    }

    try{
        trafo->set_connected(terminal->connected);
    }catch(ReadingUninitializedField* e){
        trafo->set_connected(1);
        std::cerr <<"Missing connected property in terminal " << terminal->name << std::endl;
    }

    trafo->annotation.placement.visible = true;

    std::list<PowerTransformerEndPtr>::iterator transformer_end_it;
    for (transformer_end_it = power_trafo->PowerTransformerEnd.begin();
         transformer_end_it!=power_trafo->PowerTransformerEnd.end();
         ++transformer_end_it) {
        if ((*transformer_end_it)->endNumber==1) {

            trafo->set_Sr((*transformer_end_it)->ratedS.value*1000000); // Lukas FIXME TODO: Hier muss wohl configManager.us.active_power_unit ausgewertet werden!
            trafo->set_r((*transformer_end_it)->r.value);
            trafo->set_x((*transformer_end_it)->x.value);
            trafo->set_b((*transformer_end_it)->b.value);

            if((*transformer_end_it)->RatioTapChanger != nullptr){
                if(configManager.tapStepPos == "original"){
                    trafo->set_tap_pos( (*transformer_end_it)->RatioTapChanger->step);
                }else{
                    trafo->set_tap_pos( ((*transformer_end_it)->RatioTapChanger->step - 1) * 1000);
                }

            }

            if(this->configManager.us.enable) {
                if (this->configManager.us.voltage_unit == "V") {
                    trafo->set_Vnom1((*transformer_end_it)->ratedU.value);
                } else if (this->configManager.us.voltage_unit == "kV") {
                    trafo->set_Vnom1((*transformer_end_it)->ratedU.value*1000);
                } else if (this->configManager.us.voltage_unit == "mV") {
                    trafo->set_Vnom1((*transformer_end_it)->ratedU.value*0.001);
                } else if (this->configManager.us.voltage_unit == "MV") {
                    trafo->set_Vnom1((*transformer_end_it)->ratedU.value*1000000);
                }
            }

            trafo->calc_URr();
            trafo->calc_Ukr();


        } else if ((*transformer_end_it)->endNumber==2) {

            if(this->configManager.us.enable) {
                if (this->configManager.us.voltage_unit == "V") {
                    trafo->set_Vnom2((*transformer_end_it)->ratedU.value);
                } else if (this->configManager.us.voltage_unit == "kV") {
                    trafo->set_Vnom2((*transformer_end_it)->ratedU.value*1000);
                } else if (this->configManager.us.voltage_unit == "mV") {
                    trafo->set_Vnom2((*transformer_end_it)->ratedU.value*0.001);
                } else if (this->configManager.us.voltage_unit == "MV") {
                    trafo->set_Vnom2((*transformer_end_it)->ratedU.value*1000000);
                }
            }
        }
    }

    if (this->configManager.trafo_parameters.enable) {

        SET_TRANS_EXTENT(trafo,trafo);
        trafo->annotation.placement.visible = configManager.trafo_parameters.annotation.visible;
    }

    if(power_trafo->DiagramObjects.begin() == power_trafo->DiagramObjects.end()){
        std::cerr << "Missing Diagram Object for PowerTrafo: " << power_trafo->name << " Default Position 0,0 \n";
        trafo->annotation.placement.transformation.origin.x = 0;
        trafo->annotation.placement.transformation.origin.y = 0;
        trafo->annotation.placement.transformation.rotation = 0;

        ctemplate::TemplateDictionary *powerTrafo_dict = dict->AddIncludeDictionary("TRANSFORMER_DICT");
        powerTrafo_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/Transformer.tpl");
        trafo->set_template_values(powerTrafo_dict);
    }else {
        int counter = 0;
        float currX = 0;
        float currY = 0;

        for (diagram_it = power_trafo->DiagramObjects.begin();
             diagram_it != power_trafo->DiagramObjects.end();
             ++diagram_it) {
            _t_points = this->calculate_average_position();
            currX += _t_points.xPosition;
            currY += _t_points.yPosition;
            counter += 1;
            try{
                trafo->annotation.placement.transformation.rotation = (*diagram_it)->rotation.value - 90;
            }catch(ReadingUninitializedField* e){
                trafo->annotation.placement.transformation.rotation = 0;
                std::cerr <<"Missing rotation for diagram obj" << trafo->name() << std::endl;

            }


        }
        trafo->annotation.placement.transformation.origin.x = currX/counter;
        trafo->annotation.placement.transformation.origin.y = currY/counter;

        ctemplate::TemplateDictionary *powerTrafo_dict = dict->AddIncludeDictionary("TRANSFORMER_DICT");
        powerTrafo_dict->SetFilename(
                this->configManager.ts.directory_path + "resource/" + template_folder + "/Transformer.tpl");
        trafo->set_template_values(powerTrafo_dict);

    }
    return trafo;
}

/**
 * ConductingEquipment of Terminal
 * ConductingEquipment cast to energy_consumer
 * Convert to pqload in Modelica
 */
ModPQLoad* CIMObjectHandler::EnergyConsumerHandler(BaseClass* tp_node, const TerminalPtr terminal,
                                                const EnergyConsumerPtr energy_consumer,
                                                ctemplate::TemplateDictionary *dict) {

    ModPQLoad* pqload = new ModPQLoad();

    if (this->configManager.pqload_parameters.type == 1 ) {

        pqload->set_PQLoadType(PQLoadType::Standard);

    } else if(this->configManager.pqload_parameters.type == 2){

        pqload->set_PQLoadType(PQLoadType::Profile);

    } else if(this->configManager.pqload_parameters.type == 3){

        pqload->set_PQLoadType(PQLoadType::NormProfile);
    }

    if(this->configManager.svSettings.useSVforEnergyConsumer == true){// && svPowerFlowMap[terminal] ) {
        try{
            pqload->set_Pnom(svPowerFlowMap[terminal]->p.value);
        }catch(ReadingUninitializedField* e1){
            std::cerr <<"Missing entry in PowerFlow Map: " << std::endl;
            pqload->set_Pnom(1);
        }
        try{
            pqload->set_Qnom(svPowerFlowMap[terminal]->q.value);
        }catch(ReadingUninitializedField* e1){
            std::cerr <<"Missing entry in PowerFlow Map: " << std::endl;
            pqload->set_Qnom(1);
        }

    }else{
        try{
            pqload->set_Pnom(energy_consumer->pfixed.value);
        }catch(ReadingUninitializedField* e){
            try{
                pqload->set_Pnom(energy_consumer->p.value);
            }catch(ReadingUninitializedField* e1){
                std::cerr <<"reading unititalized Pnom for PQLoad: " << std::endl;
                pqload->set_Pnom(1);
            }
        }

        try{
            pqload->set_Qnom(energy_consumer->qfixed.value);
        }catch(ReadingUninitializedField* e){
            try{
                pqload->set_Qnom(energy_consumer->q.value);
            }catch(ReadingUninitializedField* e1){
                std::cerr <<"reading unititalized Qnom for PQLoad: " << std::endl;
                pqload->set_Qnom(1);
            }
        }
    }

    pqload->set_name(name_in_modelica(energy_consumer->name));
    if (baseVoltageMap.find(energy_consumer) != baseVoltageMap.end()){
        double vnom = baseVoltageMap[energy_consumer]->nominalVoltage.value;
        if(this->configManager.us.enable) {
            if (this->configManager.us.voltage_unit == "V") {
                pqload->set_Vnom(vnom);
            } else if (this->configManager.us.voltage_unit == "kV") {
                pqload->set_Vnom(vnom * 1000);
            } else if (this->configManager.us.voltage_unit == "mV") {
                pqload->set_Vnom(vnom * 0.001);
            } else if (this->configManager.us.voltage_unit == "MV") {
                pqload->set_Vnom(vnom * 1000000);
            }
            // TODO SET DISPLAY UNIT
        }else{
            pqload->set_Vnom(vnom);
        }
    }else{
        double vnom = (((TPNodePtr)tp_node)->BaseVoltage->nominalVoltage.value);
        pqload->set_Vnom(vnom);
        std::cerr <<"No BaseVoltage for EnergyConsumer taking TPNode Voltage: " << std::endl;
    }
    if(this->configManager.us.enable){
        FIX_NEPLAN_VOLTAGE(pqload);

        if(this->configManager.us.active_power_unit == "W"){
            pqload->set_Pnom(pqload->Pnom());
        } else if(this->configManager.us.active_power_unit == "kW"){
            pqload->set_Pnom(pqload->Pnom()*1000);
        } else if(this->configManager.us.active_power_unit == "mW"){
            pqload->set_Pnom(pqload->Pnom()*0.001);
        } else if(this->configManager.us.active_power_unit == "MW"){
            pqload->set_Pnom(pqload->Pnom()*1000000);
        }

        if(this->configManager.us.reactive_power_unit == "var"){
            pqload->set_Qnom(pqload->Qnom());
        } else if(this->configManager.us.reactive_power_unit == "kvar"){
            pqload->set_Qnom(pqload->Qnom()*1000);
        } else if(this->configManager.us.reactive_power_unit == "mvar"){
            pqload->set_Qnom(pqload->Qnom()*0.001);
        } else if(this->configManager.us.reactive_power_unit == "Mvar"){
            pqload->set_Qnom(pqload->Qnom()*1000000);
        }
    }

    pqload->set_name(name_in_modelica(energy_consumer->name));
    try{
        pqload->set_sequenceNumber(terminal->sequenceNumber);
    }catch(ReadingUninitializedField* e){
        pqload->set_sequenceNumber(0);
        std::cerr <<"Missing sequence number in terminal sequence number " << terminal->name << std::endl;
    }
    pqload->set_connected(terminal->connected);
    pqload->annotation.placement.visible = true;

    if (this->configManager.pqload_parameters.enable) {

        SET_TRANS_EXTENT(pqload,pqload);
        pqload->annotation.placement.visible = configManager.pqload_parameters.annotation.visible;
        pqload->set_profileName(configManager.pqload_parameters.profile_name);
        pqload->set_profileFileName(configManager.pqload_parameters.profile_filename);
    }

    if(energy_consumer->DiagramObjects.begin() == energy_consumer->DiagramObjects.end()){
        std::cerr << "Missing Diagram Object for EnergyConsumer: " << energy_consumer->name << " Default Position 0,0 \n";
        pqload->annotation.placement.transformation.origin.x = 0;
        pqload->annotation.placement.transformation.origin.y = 0;
        pqload->annotation.placement.transformation.rotation = 0;

        if(this->configManager.household_parameters.use_households == false){
            if (pqload->sequenceNumber() == 0 || pqload->sequenceNumber() == 1) {

                if (this->configManager.pqload_parameters.type == 1 && pqload->PQLoadType() == PQLoadType::Standard) {
                    ctemplate::TemplateDictionary *pqLoad_dict = dict->AddIncludeDictionary("PQLOAD_DICT");
                    pqLoad_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PQLoad.tpl");
                    pqload->set_template_values(pqLoad_dict);

                } else if(this->configManager.pqload_parameters.type == 2 && pqload->PQLoadType() == PQLoadType::Profile){
                    ctemplate::TemplateDictionary *pqLoad_dict = dict->AddIncludeDictionary("PQLOAD_PROFILE_DICT");
                    pqLoad_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PQLoadProfile.tpl");
                    pqload->set_template_values(pqLoad_dict);

                } else if(this->configManager.pqload_parameters.type == 3 && pqload->PQLoadType() == PQLoadType::NormProfile){
                    ctemplate::TemplateDictionary *pqLoad_dict = dict->AddIncludeDictionary("PQLOAD_NORM_PROFILE_DICT");
                    pqLoad_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PQLoadNormProfile.tpl");
                    pqload->set_template_values(pqLoad_dict);
                }
            }
        }
    }else{
        int counter = 0;
        float currX = 0;
        float currY = 0;

        for (diagram_it = energy_consumer->DiagramObjects.begin(); diagram_it!=energy_consumer->DiagramObjects.end();
             ++diagram_it) {
            _t_points = this->calculate_average_position();
            currX += _t_points.xPosition;
            currY += _t_points.yPosition;
            counter += 1;
            try{
                pqload->annotation.placement.transformation.rotation = (*diagram_it)->rotation.value;
            }catch(ReadingUninitializedField* e){
                pqload->annotation.placement.transformation.rotation = 0;
                std::cerr <<"Missing rotation for diagram obj of pq load"<< energy_consumer->name << std::endl;
            }

        }

        pqload->annotation.placement.transformation.origin.x = currX /counter;
        pqload->annotation.placement.transformation.origin.y = currY /counter;


        if(this->configManager.household_parameters.use_households == false){
            if (pqload->sequenceNumber() == 0 || pqload->sequenceNumber() == 1) {

                if (this->configManager.pqload_parameters.type == 1 && pqload->PQLoadType() == PQLoadType::Standard) {
                    ctemplate::TemplateDictionary *pqLoad_dict = dict->AddIncludeDictionary("PQLOAD_DICT");
                    pqLoad_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PQLoad.tpl");
                    pqload->set_template_values(pqLoad_dict);

                } else if(this->configManager.pqload_parameters.type == 2 && pqload->PQLoadType() == PQLoadType::Profile){
                    ctemplate::TemplateDictionary *pqLoad_dict = dict->AddIncludeDictionary("PQLOAD_PROFILE_DICT");
                    pqLoad_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PQLoadProfile.tpl");
                    pqload->set_template_values(pqLoad_dict);

                } else if(this->configManager.pqload_parameters.type == 3 && pqload->PQLoadType() == PQLoadType::NormProfile){
                    ctemplate::TemplateDictionary *pqLoad_dict = dict->AddIncludeDictionary("PQLOAD_NORM_PROFILE_DICT");
                    pqLoad_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PQLoadNormProfile.tpl");
                    pqload->set_template_values(pqLoad_dict);
                }
            }
        }
    }
    return pqload;
}

/**
* ConductingEquipment of Terminal
* ConductingEquipment cast to SynchronousMachine
* Convert to SolarGenerator in Modelica
*/
ModSolarGenerator* CIMObjectHandler::SynchronousMachineHandlerType2(const TerminalPtr terminal,
                                                                 const SynMachinePtr syn_machine,
                                                                 ctemplate::TemplateDictionary *dict) {
    ModSolarGenerator* solar_generator = new ModSolarGenerator();

    solar_generator->set_name(name_in_modelica(syn_machine->name));
    solar_generator->annotation.placement.visible = true;
    solar_generator->set_connected(terminal->connected);

    try{
        solar_generator->set_sequenceNumber(terminal->sequenceNumber);
    }catch(ReadingUninitializedField* e){
        solar_generator->set_sequenceNumber(0);
        std::cerr <<"Missing sequence number in terminal sequence number " << terminal << std::endl;
    }

    if (this->configManager.solar_gen_parameters.enable) {
        SET_TRANS_EXTENT(solar_generator,solar_gen);
        solar_generator->annotation.placement.visible = configManager.solar_gen_parameters.annotation.visible;
    }
    if(syn_machine->DiagramObjects.begin() == syn_machine->DiagramObjects.end()){
        std::cerr << "Missing Diagram Object for SyncronousMachine2: " << syn_machine->name << " Default Position 0,0 \n";
        solar_generator->annotation.placement.transformation.origin.x = 0;
        solar_generator->annotation.placement.transformation.origin.y = 0;
        solar_generator->annotation.placement.transformation.rotation = 0;

        if (this->configManager.solar_gen_parameters.enable) {
            if (this->configManager.household_parameters.use_households == false) {

                if (solar_generator->sequenceNumber()==0 || solar_generator->sequenceNumber()==1) {
                    ctemplate::TemplateDictionary *solar_generator_dict = dict->AddIncludeDictionary(
                            "SOLARGENERATOR_DICT");
                    solar_generator_dict->SetFilename(
                            this->configManager.ts.directory_path + "resource/" + template_folder + "/SolarGenerator.tpl");
                    solar_generator->set_template_values(solar_generator_dict);
                }
            }
        }
    }
    for (diagram_it = syn_machine->DiagramObjects.begin();
         diagram_it!=syn_machine->DiagramObjects.end();
         ++diagram_it) {
        _t_points = this->calculate_average_position();
        solar_generator->annotation.placement.transformation.origin.x = _t_points.xPosition;
        solar_generator->annotation.placement.transformation.origin.y = _t_points.yPosition;
        solar_generator->annotation.placement.transformation.rotation = (*diagram_it)->rotation.value;

        if (this->configManager.solar_gen_parameters.enable) {
            if (this->configManager.household_parameters.use_households == false) {

                if (solar_generator->sequenceNumber()==0 || solar_generator->sequenceNumber()==1) {
                    ctemplate::TemplateDictionary *solar_generator_dict = dict->AddIncludeDictionary(
                            "SOLARGENERATOR_DICT");
                    solar_generator_dict->SetFilename(
                            this->configManager.ts.directory_path + "resource/" + template_folder + "/SolarGenerator.tpl");
                    solar_generator->set_template_values(solar_generator_dict);
                }
            }
        }
    }

    return solar_generator;
}

/**
 * ConductingEquipment of Terminal
 * ConductingEquipment cast to SynchronousMachine
 * Convert to WindGenerator in Modelica
 */
ModWindGenerator* CIMObjectHandler::SynchronousMachineHandlerType1(const TerminalPtr terminal,
                                                                const SynMachinePtr syn_machine,
                                                                ctemplate::TemplateDictionary *dict) {
    ModWindGenerator* wind_generator = new ModWindGenerator();

    wind_generator->set_name(name_in_modelica(syn_machine->name));
    try{
        wind_generator->set_sequenceNumber(terminal->sequenceNumber);
    }catch(ReadingUninitializedField* e){
        wind_generator->set_sequenceNumber(0);
        std::cerr <<"Missing sequence number in terminal sequence number " << terminal << std::endl;
    }
    wind_generator->set_connected(terminal->connected);
    wind_generator->annotation.placement.visible = true;

    if (this->configManager.wind_gen_parameters.enable) {
        SET_TRANS_EXTENT(wind_generator,wind_gen);
        wind_generator->annotation.placement.visible = configManager.wind_gen_parameters.annotation.visible;
    }

    if(syn_machine->DiagramObjects.begin() == syn_machine->DiagramObjects.end()){
        std::cerr << "Missing Diagram Object for SynchronousMachine: " << syn_machine->name << " Default Position 0,0 \n";
        wind_generator->annotation.placement.transformation.origin.x = 0;
        wind_generator->annotation.placement.transformation.origin.y = 0;
        wind_generator->annotation.placement.transformation.rotation = 0;

        if (wind_generator->sequenceNumber()==0 || wind_generator->sequenceNumber()==1) {
            ctemplate::TemplateDictionary *wind_generator_dict = dict->AddIncludeDictionary("WINDGENERATOR_DICT");
            wind_generator_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/WindGenerator.tpl");
            wind_generator->set_template_values(wind_generator_dict);
        }
    }

    for (diagram_it = syn_machine->DiagramObjects.begin();
         diagram_it!=syn_machine->DiagramObjects.end();
         ++diagram_it) {
        _t_points = this->calculate_average_position();
        wind_generator->annotation.placement.transformation.origin.x = _t_points.xPosition;
        wind_generator->annotation.placement.transformation.origin.y = _t_points.yPosition;
        wind_generator->annotation.placement.transformation.rotation = (*diagram_it)->rotation.value;

        if (wind_generator->sequenceNumber()==0 || wind_generator->sequenceNumber()==1) {
            ctemplate::TemplateDictionary *wind_generator_dict = dict->AddIncludeDictionary("WINDGENERATOR_DICT");
            wind_generator_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/WindGenerator.tpl");
            wind_generator->set_template_values(wind_generator_dict);
        }
    }

    return wind_generator;
}

ModBreaker* CIMObjectHandler::BreakerHandler(BusBar* busbar, const TerminalPtr terminal, const BreakerPtr cim_breaker,ctemplate::TemplateDictionary* dict){
    ModBreaker* breaker = new ModBreaker();
    breaker->set_name(name_in_modelica(cim_breaker->name));
    breaker->set_is_closed(!cim_breaker->normalOpen);
    // TODO set Vnom
    try{
        breaker->set_connected(terminal->connected);
    }catch(ReadingUninitializedField* e){
        breaker->set_connected(0);
        std::cerr <<"Missing connected state in terminal sequence number " << terminal << std::endl;
    }
    try{
        if(terminal->sequenceNumber == 2) {
            breaker->setBus2(busbar);
        }else{
            breaker->setBus1(busbar);
        }
    }catch(ReadingUninitializedField* e){
        breaker->setBus1(busbar);
        std::cerr <<"Missing sequence number in terminal sequence number " << terminal << std::endl;
    }

    if(cim_breaker->DiagramObjects.begin() == cim_breaker->DiagramObjects.end()){
        std::cerr << "Missing Diagram Object for Switch: " << cim_breaker->name << " Default Position 0,0 \n";
        breaker->annotation.placement.transformation.origin.x = 0;
        breaker->annotation.placement.transformation.origin.y = 0;
        breaker->annotation.placement.transformation.rotation = 0;

        ctemplate::TemplateDictionary *breaker_dict = dict->AddIncludeDictionary("BREAKER_DICT");
        breaker_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/Breaker.tpl");
        breaker->set_template_values(breaker_dict);
    }else{
        int counter = 0;
        float currX = 0;
        float currY = 0;
        for (diagram_it = cim_breaker->DiagramObjects.begin();
             diagram_it!= cim_breaker->DiagramObjects.end();
             ++diagram_it) {            _t_points = this->calculate_average_position();
            currX += _t_points.xPosition;
            currY += _t_points.yPosition;
            counter += 1;

        }
        try{
            breaker->annotation.placement.transformation.rotation = (*cim_breaker->DiagramObjects.begin())->rotation.value;
        }catch(ReadingUninitializedField* e){
            breaker->annotation.placement.transformation.rotation = 0;
            std::cerr <<"Missing rotation for diagram obj" << breaker->name()<< std::endl;
        }
        breaker->annotation.placement.transformation.origin.x = currX /counter;
        breaker->annotation.placement.transformation.origin.y = currY /counter;


        ctemplate::TemplateDictionary *breaker_dict = dict->AddIncludeDictionary("BREAKER_DICT");
        breaker_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/Breaker.tpl");
        breaker->set_template_values(breaker_dict);

    }
    return breaker;
}


/**
 * ConductingEquipment of Terminal
 * ConductingEquipment cast to SynchronousMachineDynamic
 * Convert to synchMachineDynamic in Modelica
 */

SynMachineDyn * CIMObjectHandler::synMachineDynHandler(BaseClass* node, const TerminalPtr terminal,
                                                       const SynMachineDynPtr syn_machine,
                                                       ctemplate::TemplateDictionary* dict){

    SynMachineDyn * synMachineDyn = new SynMachineDyn();
    synMachineDyn->set_name(name_in_modelica(syn_machine->name));

    try{
        synMachineDyn->set_sequenceNumber(terminal->sequenceNumber);
    }catch(ReadingUninitializedField* e){
        synMachineDyn->set_sequenceNumber(0);
        std::cerr <<"Missing sequence number in terminal sequence number " << terminal->name << std::endl;
    }
    try{
        synMachineDyn->set_connected(terminal->connected);
    }catch(ReadingUninitializedField* e){
        synMachineDyn->set_connected(1);
        std::cerr <<"Missing connected property in terminal " << terminal->name << std::endl;
    }
    synMachineDyn->annotation.placement.visible = true;

    double v_unit_conversion=1;
    double s_unit_conversion=1;
    if(this->configManager.us.active_power_unit == "W"){
        s_unit_conversion = 1;
    } else if(this->configManager.us.active_power_unit == "kW"){
        s_unit_conversion =  1000;
    } else if(this->configManager.us.active_power_unit == "mW"){
        s_unit_conversion =  0.001;
    } else if(this->configManager.us.active_power_unit == "MW"){
        s_unit_conversion =  1000000;
    }
    if(this->configManager.us.voltage_unit == "V"){
        v_unit_conversion = 1;
    } else if(this->configManager.us.voltage_unit == "kV"){
        v_unit_conversion =  1000;
    } else if(this->configManager.us.voltage_unit == "mV"){
        v_unit_conversion =  0.001;
    } else if(this->configManager.us.voltage_unit == "MV"){
        v_unit_conversion =  1000000;
    }

    synMachineDyn->set_raPu((syn_machine)->statorResistance.value);
    synMachineDyn->set_xdPU(syn_machine->xDirectSync.value);
    synMachineDyn->set_xlPu(syn_machine->statorLeakageReactance.value);
    synMachineDyn->set_xpdPu(syn_machine->xDirectTrans.value);
    synMachineDyn->set_xppdPu(syn_machine->xDirectSubtrans.value);
    synMachineDyn->set_xppqPu(syn_machine->xQuadSubtrans.value);
    synMachineDyn->set_xpqPu(syn_machine->xQuadTrans.value);
    synMachineDyn->set_xqPu(syn_machine->xQuadSync.value);
    synMachineDyn->set_Tpd0(syn_machine->tpdo.value);
    synMachineDyn->set_Tppd0(syn_machine->tppdo.value);
    synMachineDyn->set_Tppq0(syn_machine->tppqo.value);
    synMachineDyn->set_Tpq0(syn_machine->tpqo.value);
    // TODO: change hard-coded unit conversion
    synMachineDyn->set_SNom(syn_machine->SynchronousMachine->ratedS.value * s_unit_conversion);
    synMachineDyn->set_VNom(syn_machine->SynchronousMachine->ratedU.value * v_unit_conversion);
    synMachineDyn->set_inertia(syn_machine->inertia.value);

    // TODO MBY NEW SVVOLTAGE/PWRFLOW OPTION
    if(this->configManager.svSettings.useSVforGeneratingUnit == true ) {//&& svPowerFlowMap[terminal] && svVoltageMap[tp_node]){


        try {
            // TODO CONVERSION TO RADIANS
            // Junjie: No need, I updated conversion inside templates
            synMachineDyn->set_UPhaseStart( svVoltageMap[node]->angle.value);
        } catch (ReadingUninitializedField *e) {
            std::cerr << "No SVVoltage at tp node for SynMachineDyn" << terminal->name << std::endl;
        }
        try {
            synMachineDyn->set_UStart(svVoltageMap[node]->v.value * v_unit_conversion);
        }
        catch (ReadingUninitializedField *e)
        {
            std::cerr << "No SVVoltage at tp node for SynMachineDyn" << terminal->name << std::endl;
        }
        try {
            synMachineDyn->set_QStart(svPowerFlowMap[terminal]->q.value * s_unit_conversion);
        } catch (ReadingUninitializedField *e) {
            std::cerr << "No SVPowerFlow at tp node for SynMachineDyn" << terminal->name << std::endl;
        }
        try {
            synMachineDyn->set_PStart(svPowerFlowMap[terminal]->p.value * s_unit_conversion);
        } catch (ReadingUninitializedField *e) {
            std::cerr << "No SVPowerFlow at tp node for SynMachineDyn" << terminal->name << std::endl;
        }

    }
    auto syn_machine_stat=syn_machine->SynchronousMachine;
    if(syn_machine_stat->DiagramObjects.begin() == syn_machine_stat->DiagramObjects.end()){
        std::cerr << "Missing Diagram Object for SynchronousMachine: " << syn_machine->name << " Default Position 0,0 \n";
        synMachineDyn->annotation.placement.transformation.origin.x = 0;
        synMachineDyn->annotation.placement.transformation.origin.y = 0;
        synMachineDyn->annotation.placement.transformation.rotation = 0;

        ctemplate::TemplateDictionary *synMachineDyn_dict = dict->AddIncludeDictionary("SynchronousMachine4Windings_DICT");
        synMachineDyn_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/SynchronousMachine4Windings.tpl");
        synMachineDyn->set_template_values(synMachineDyn_dict);
    }else{
        int counter = 0;
        float currX = 0;
        float currY = 0;
        for (diagram_it = syn_machine_stat->DiagramObjects.begin();
             diagram_it!= syn_machine_stat->DiagramObjects.end();
             ++diagram_it) {            _t_points = this->calculate_average_position();
            currX += _t_points.xPosition;
            currY += _t_points.yPosition;
            counter += 1;

            try{
                synMachineDyn->annotation.placement.transformation.rotation = (*diagram_it)->rotation.value;
            }catch(ReadingUninitializedField* e){
                synMachineDyn->annotation.placement.transformation.rotation = 0;
                std::cerr <<"Missing rotation for diagram obj" << synMachineDyn->name()<< std::endl;

            }
        }

        synMachineDyn->annotation.placement.transformation.origin.x = currX /counter;
        synMachineDyn->annotation.placement.transformation.origin.y = currY /counter;


        ctemplate::TemplateDictionary *synMachineDyn_dict = dict->AddIncludeDictionary("SynchronousMachine4Windings_DICT");
        synMachineDyn_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/SynchronousMachine4Windings.tpl");
        synMachineDyn->set_template_values(synMachineDyn_dict);

    }

    return synMachineDyn;



}


/**
 * ConductingEquipment of Terminal
 * ConductingEquipment cast to SynchronousMachine
 * Convert to PVNode in Modelica
 */

ModPVNode * CIMObjectHandler::SynchronousMachineHandlerType0(BaseClass* tp_node, const TerminalPtr terminal,
                                                          const SynMachinePtr syn_machine,
                                                          ctemplate::TemplateDictionary *dict) {
    ModPVNode* pv_node = new ModPVNode();
    pv_node->set_name(name_in_modelica(syn_machine->name));
    try{
        pv_node->set_sequenceNumber(terminal->sequenceNumber);
    }catch(ReadingUninitializedField* e){
        pv_node->set_sequenceNumber(0);
        std::cerr <<"Missing sequence number in terminal sequence number " << terminal->name << std::endl;
    }
    try{
        pv_node->set_connected(terminal->connected);
    }catch(ReadingUninitializedField* e){
        pv_node->set_connected(1);
        std::cerr <<"Missing connected property in terminal " << terminal->name << std::endl;
    }
    pv_node->annotation.placement.visible = true;

    if(this->configManager.us.enable){
        try {
            if(this->configManager.us.voltage_unit == "V"){
                pv_node->setVnom((syn_machine)->ratedU.value);
            } else if(this->configManager.us.voltage_unit == "kV"){
                pv_node->setVnom((syn_machine)->ratedU.value * 1000);
            } else if(this->configManager.us.voltage_unit == "mV"){
                pv_node->setVnom((syn_machine)->ratedU.value * 0.001);
            } else if(this->configManager.us.voltage_unit == "MV"){
                pv_node->setVnom((syn_machine)->ratedU.value * 1000000);
            }
        }catch(ReadingUninitializedField* e) {
            if(baseVoltageMap.find(syn_machine)!= baseVoltageMap.end()){
                if (this->configManager.us.voltage_unit == "V") {
                    pv_node->setVnom(baseVoltageMap[syn_machine]->nominalVoltage.value);
                } else if (this->configManager.us.voltage_unit == "kV") {
                    pv_node->setVnom(baseVoltageMap[syn_machine]->nominalVoltage.value * 1000);
                } else if (this->configManager.us.voltage_unit == "mV") {
                    pv_node->setVnom(baseVoltageMap[syn_machine]->nominalVoltage.value * 0.001);
                } else if (this->configManager.us.voltage_unit == "MV") {
                    pv_node->setVnom(baseVoltageMap[syn_machine]->nominalVoltage.value * 1000000);
                }
                std::cerr << "Unitialized Vnom for Synchronous Machine taking TopologicalNode BaseVoltage "
                          << std::endl;
            }
            else{
                std::cerr << "Synchronous Machine without ratedU and BaseVoltage" << syn_machine->name
                          << std::endl;
            }
        }

    }

    if(this->configManager.svSettings.useSVforGeneratingUnit == true ){//&& svPowerFlowMap[terminal] && svVoltageMap[tp_node]){

        if(this->configManager.us.enable){
            if(this->configManager.us.active_power_unit == "W"){
                pv_node->setPgen(-svPowerFlowMap[terminal]->p.value);
            } else if(this->configManager.us.active_power_unit == "kW"){
                pv_node->setPgen(-svPowerFlowMap[terminal]->p.value * 1000);
            } else if(this->configManager.us.active_power_unit == "mW"){
                pv_node->setPgen(-svPowerFlowMap[terminal]->p.value * 0.001);
            } else if(this->configManager.us.active_power_unit == "MW"){
                pv_node->setPgen(-svPowerFlowMap[terminal]->p.value * 1000000);
            }
            if(this->configManager.ss.use_TPNodes == true){
                if(this->configManager.us.voltage_unit == "V"){
                    pv_node->setVabs(svVoltageMap[tp_node]->v.value);
                } else if(this->configManager.us.voltage_unit == "kV"){
                    pv_node->setVabs(svVoltageMap[tp_node]->v.value * 1000);
                } else if(this->configManager.us.voltage_unit == "mV"){
                    pv_node->setVabs(svVoltageMap[tp_node]->v.value * 0.001);
                } else if(this->configManager.us.voltage_unit == "MV"){
                    pv_node->setVabs(svVoltageMap[tp_node]->v.value * 1000000);
                }
            }else if(syn_machine->RegulatingControl != nullptr){
                if(this->configManager.us.voltage_unit == "V"){
                    pv_node->setVabs((syn_machine)->RegulatingControl->targetValue);
                } else if(this->configManager.us.voltage_unit == "kV"){
                    pv_node->setVabs((syn_machine)->RegulatingControl->targetValue * 1000);
                } else if(this->configManager.us.voltage_unit == "mV"){
                    pv_node->setVabs((syn_machine)->RegulatingControl->targetValue * 0.001);
                } else if(this->configManager.us.voltage_unit == "MV"){
                    pv_node->setVabs((syn_machine)->RegulatingControl->targetValue * 1000000);
                }
            }else{
                pv_node->setVabs(pv_node->Vnom());
            }


        }


    }else{

        if(this->configManager.us.enable) {
            if (this->configManager.us.active_power_unit == "W") {
                pv_node->setPgen(generatorMap[syn_machine]->initialP.value);
            } else if (this->configManager.us.active_power_unit == "kW") {
                pv_node->setPgen(generatorMap[syn_machine]->initialP.value * 1000);
            } else if (this->configManager.us.active_power_unit == "mW") {
                pv_node->setPgen(generatorMap[syn_machine]->initialP.value * 0.001);
            } else if (this->configManager.us.active_power_unit == "MW") {
                pv_node->setPgen(generatorMap[syn_machine]->initialP.value * 1000000);
            }
            if(syn_machine->RegulatingControl != nullptr){
                if(this->configManager.us.voltage_unit == "V"){
                    pv_node->setVabs((syn_machine)->RegulatingControl->targetValue);
                } else if(this->configManager.us.voltage_unit == "kV"){
                    pv_node->setVabs((syn_machine)->RegulatingControl->targetValue * 1000);
                } else if(this->configManager.us.voltage_unit == "mV"){
                    pv_node->setVabs((syn_machine)->RegulatingControl->targetValue * 0.001);
                } else if(this->configManager.us.voltage_unit == "MV"){
                    pv_node->setVabs((syn_machine)->RegulatingControl->targetValue * 1000000);
                }
            }else{
                pv_node->setVabs(pv_node->Vnom());
            }
        }

    }

    if(syn_machine->DiagramObjects.begin() == syn_machine->DiagramObjects.end()){
        std::cerr << "Missing Diagram Object for SynchronousMachine: " << syn_machine->name << " Default Position 0,0 \n";
        pv_node->annotation.placement.transformation.origin.x = 0;
        pv_node->annotation.placement.transformation.origin.y = 0;
        pv_node->annotation.placement.transformation.rotation = 0;

        ctemplate::TemplateDictionary *pv_node_dict = dict->AddIncludeDictionary("PVNODE_DICT");
        pv_node_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PVNode.tpl");
        pv_node->set_template_values(pv_node_dict);
    }else{
        int counter = 0;
        float currX = 0;
        float currY = 0;
        for (diagram_it = syn_machine->DiagramObjects.begin();
             diagram_it!= syn_machine->DiagramObjects.end();
             ++diagram_it) {            _t_points = this->calculate_average_position();
            currX += _t_points.xPosition;
            currY += _t_points.yPosition;
            counter += 1;

            try{
                pv_node->annotation.placement.transformation.rotation = (*diagram_it)->rotation.value;
            }catch(ReadingUninitializedField* e){
                pv_node->annotation.placement.transformation.rotation = 0;
                std::cerr <<"Missing rotation for diagram obj" << pv_node->name()<< std::endl;

            }
        }

        pv_node->annotation.placement.transformation.origin.x = currX /counter;
        pv_node->annotation.placement.transformation.origin.y = currY /counter;

        ctemplate::TemplateDictionary *pv_node_dict = dict->AddIncludeDictionary("PVNODE_DICT");
        pv_node_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/PVNode.tpl");
        pv_node->set_template_values(pv_node_dict);

    }

    return pv_node;
}


#ifdef SINERGIEN
Battery CIMObjectHandler::BatteryStorageHandler(const TPNodePtr tp_node, const TerminalPtr terminal, const BatteryStoragePtr battery_storge,
                                                ctemplate::TemplateDictionary* dict){

  Battery battery;

  if (this->configManager.pqload_parameters.type == 0 ){
    battery.set_BatteryType(BatteryType::Type0);
  } else if(this->configManager.pqload_parameters.type == 1){
    battery.set_BatteryType(BatteryType::Type1);
  }
  battery.set_name(name_in_modelica(battery_storge->name));
  battery.set_sequenceNumber(terminal->sequenceNumber);
  battery.set_connected(terminal->connected);
  battery.set_Cnom(battery_storge->capacity.value);

  if (this->configManager.battery_parameters.enable) {
    SET_TRANS_EXTENT(battery,battery);
    battery.annotation.placement.visible = configManager.battery_parameters.annotation.visible;
  }

    if (battery_storge->DiagramObjects.begin() == battery_storge->DiagramObjects.end()) {

        std::cerr << "Missing Diagram Object for BatteryStorage: " << battery_storge->name << " Default Position 0,0 \n";
        battery.annotation.placement.transformation.origin.x = 0;
        battery.annotation.placement.transformation.origin.y = 0;
        battery.annotation.placement.transformation.rotation = 0;

        if (battery.sequenceNumber() == 0 || battery.sequenceNumber() == 1) {
            if (this->configManager.pqload_parameters.type == 0 && battery.BatteryType() == BatteryType::Type0) {
                ctemplate::TemplateDictionary *battery_dict = dict->AddIncludeDictionary("BATTERY_TYPE0_DICT");
                battery_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/BatteryType0.tpl");
                battery.set_template_values(battery_dict);

            } else if (this->configManager.pqload_parameters.type == 1 && battery.BatteryType() == BatteryType::Type1) {
                ctemplate::TemplateDictionary *battery_dict = dict->AddIncludeDictionary("BATTERY_TYPE1_DICT");
                battery_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/BatteryType1.tpl");
                battery.set_template_values(battery_dict);
            }
        }
    }
  for (diagram_it = battery_storge->DiagramObjects.begin();
       diagram_it != battery_storge->DiagramObjects.end();
       ++diagram_it) {

    _t_points = this->calculate_average_position();
    battery.annotation.placement.transformation.origin.x = _t_points.xPosition;
    battery.annotation.placement.transformation.origin.y = _t_points.yPosition;
    battery.annotation.placement.transformation.rotation = (*diagram_it)->rotation.value;

    if (battery.sequenceNumber()==0 || battery.sequenceNumber()==1) {
      if (this->configManager.pqload_parameters.type == 0 && battery.BatteryType() == BatteryType::Type0) {
        ctemplate::TemplateDictionary *battery_dict = dict->AddIncludeDictionary("BATTERY_TYPE0_DICT");
        battery_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/BatteryType0.tpl");
        battery.set_template_values(battery_dict);

      } else if(this->configManager.pqload_parameters.type == 1 && battery.BatteryType() == BatteryType::Type1){
        ctemplate::TemplateDictionary *battery_dict = dict->AddIncludeDictionary("BATTERY_TYPE1_DICT");
        battery_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/BatteryType1.tpl");
        battery.set_template_values(battery_dict);
      }
    }
  }

  return battery;

}
#endif


/**
 * Create Connection
 */
bool CIMObjectHandler::ConnectionHandler(ctemplate::TemplateDictionary *dict) {

    unsigned int size;
    size = connectionQueue.size();

    while (!connectionQueue.empty()) {
        ctemplate::TemplateDictionary *connection_dict = dict->AddIncludeDictionary("CONNECTIONS_DICT");
        connection_dict->SetFilename(this->configManager.ts.directory_path + "resource/" + template_folder + "/Connections.tpl");
        if (connectionQueue.front().is_connected()) {
            connection_dict->AddSectionDictionary("CONNECTED_SECTION");
        } else {
            connection_dict->AddSectionDictionary("UNCONNECTED_SECTION");
        }

        connectionQueue.front().draw_connection(connection_dict);

        connectionQueue.pop();
    }

    return true;
}

/**
 *  every component from NEPLAN has two position
 *  calculate the average position
 *  td::list<DiagramObjectPtr>::iterator diagram_it is class member!
 */
DiagramObjectPoint CIMObjectHandler::calculate_average_position() {
    DiagramObjectPoint t_points;
    t_points.xPosition = 0;
    t_points.yPosition = 0;

    std::list<DiagramObjectPointPtr>::iterator points_it;
    for (points_it = (*diagram_it)->DiagramObjectPoints.begin();
         points_it!= (*diagram_it)->DiagramObjectPoints.end();
         ++points_it) {
        t_points.xPosition = (*points_it)->xPosition + t_points.xPosition;
        t_points.yPosition = (*points_it)->yPosition + t_points.yPosition;
    }


    std::size_t size = (*diagram_it)->DiagramObjectPoints.size();
    t_points = convert_coordinate(t_points.xPosition/size, t_points.yPosition/size, this->configManager);
    return t_points;
}

/**
 * convert the coordinate system between different software
 */
DiagramObjectPoint CIMObjectHandler::convert_coordinate(double x, double y, const ConfigManager &configManager) {

    double trans_para[4] = {1, 0, -1, 0};
    if (configManager.ss.enable) {
        for (int i = 0; i < 4; ++i)
            trans_para[i] = configManager.ss.topology_trans_parameter[i];
    }
    DiagramObjectPoint t_points;
    t_points.xPosition = trans_para[0]*x + trans_para[1];
    t_points.yPosition = trans_para[2]*y + trans_para[3];
    return t_points;
}

/**
 * convert name adapt to the format in modelica
 */
std::string CIMObjectHandler::name_in_modelica(std::string original_name) {
    std::string t_name = "CIM_" + original_name; ///some names illegal in modelica!
    for (std::string::iterator it = t_name.begin(); it!=t_name.end(); ++it) {
        if ((*it==' ') || (*it=='-') || (*it=='.')) {
            *it = '_';
        }
    }

    return t_name;
}