private void WriteConfig(int run, int trial, SoaConfig config)
        {
            int    numTrialDigits    = numTrialsPerRun.ToString().Length;
            string trialNumberFormat = "D" + numTrialDigits.ToString();

            Directory.CreateDirectory(soaConfigOutputPath);

            string runFolder = Path.Combine(soaConfigOutputPath, "Run_" + run.ToString(trialNumberFormat));

            Directory.CreateDirectory(runFolder);

            string trialFolder = Path.Combine(runFolder, experiment.GetTrialName());

            Directory.CreateDirectory(trialFolder);

            string configName = Path.Combine(trialFolder, "SoaSimConfig.xml");

            Log.debug("Generating File: " + configName);

            Log.debug("***");
            Log.debug(generatorRandomSeed.ToString());
            Log.debug("***");

            SoaConfigXMLWriter.Write(config, configName);
        }
        public void SetSiteLocations(SoaConfig soaConfig)
        {
            // Blue Base
            blueBases = new List <SiteConfig>();
            blueBases.Add(new BlueBaseConfig(-3.02830208f, -9.7492255f, "Blue Base", new Optional <float>(soaConfig.defaultCommsRanges["BlueBase"])));

            // Red Base
            redBases = new List <SiteConfig>();
            redBases.Add(new RedBaseConfig(-17.7515077f, 13.7463599f, "Red Base 0"));
            redBases.Add(new RedBaseConfig(-0.439941213f, 12.7518844f, "Red Base 1"));
            redBases.Add(new RedBaseConfig(22.0787984f, 10.7493104f, "Red Base 2"));

            // NGO Site
            ngoSites = new List <SiteConfig>();
            ngoSites.Add(new NGOSiteConfig(-21.2181483f, -1.25010618f, "NGO Site 0"));
            ngoSites.Add(new NGOSiteConfig(-4.76803318f, -5.74888572f, "NGO Site 1"));
            ngoSites.Add(new NGOSiteConfig(11.6916982f, 4.76402643f, "NGO Site 2"));
            ngoSites.Add(new NGOSiteConfig(24.6807822f, -6.75057337f, "NGO Site 3"));

            // Village
            villages = new List <SiteConfig>();
            villages.Add(new VillageConfig(-16.0197901f, 5.74808437f, "Village 0"));
            villages.Add(new VillageConfig(-14.296086f, -3.22944096f, "Village 1"));
            villages.Add(new VillageConfig(-5.63349131f, 4.74559538f, "Village 2"));
            villages.Add(new VillageConfig(7.34998325f, -0.743652906f, "Village 3"));
            villages.Add(new VillageConfig(-13.4306279f, -11.7638197f, "Village 4"));

            // Add all to soaConfig
            soaConfig.sites.AddRange(blueBases);
            soaConfig.sites.AddRange(redBases);
            soaConfig.sites.AddRange(ngoSites);
            soaConfig.sites.AddRange(villages);
        }
        private static void PopulateRemote(XmlDocument xmlDoc, XmlNode configNode, SoaConfig soaConfig)
        {
            // Create "Remote" node and append to configNode
            XmlNode node = xmlDoc.CreateElement("Remote");

            configNode.AppendChild(node);

            // Go through each remote platform and add children to "Remote" node
            foreach (PlatformConfig p in soaConfig.remotePlatforms)
            {
                switch (p.GetConfigType())
                {
                case PlatformConfig.ConfigType.HEAVY_UAV:
                    PopulateHeavyUAV(xmlDoc, node, (HeavyUAVConfig)p);
                    break;

                case PlatformConfig.ConfigType.SMALL_UAV:
                    PopulateSmallUAV(xmlDoc, node, (SmallUAVConfig)p);
                    break;

                case PlatformConfig.ConfigType.BLUE_BALLOON:
                    PopulateBlueBalloon(xmlDoc, node, (BlueBalloonConfig)p);
                    break;

                default:
                    Log.error("SoaConfigXMLWriter::PopulateRemote(): Unrecognized config type " + p.GetConfigType() + " in soaConfig.remotePlatforms");
                    break;
                }
            }
        }
 public void SetSiteLocations(SoaConfig soaConfig)
 {
     // Add all to soaConfig
     soaConfig.sites.AddRange(blueBases);
     soaConfig.sites.AddRange(redBases);
     soaConfig.sites.AddRange(ngoSites);
     soaConfig.sites.AddRange(villages);
 }
 public void SetCommsDefaults(SoaConfig soaConfig)
 {
     soaConfig.defaultCommsRanges["BlueBase"]    = 10.0f;
     soaConfig.defaultCommsRanges["RedDismount"] = 5.0f;
     soaConfig.defaultCommsRanges["RedTruck"]    = 5.0f;
     soaConfig.defaultCommsRanges["BluePolice"]  = 10.0f;
     soaConfig.defaultCommsRanges["HeavyUAV"]    = 10.0f;
     soaConfig.defaultCommsRanges["SmallUAV"]    = 10.0f;
 }
        private void SetClassifierDefaults(SoaConfig soaConfig)
        {
            // Pointer
            List <PerceptionModality> modes;

            // Red Dismount
            modes = new List <PerceptionModality>();
            modes.Add(new PerceptionModality("BluePolice", 5.0f, 5.0f));
            modes.Add(new PerceptionModality("HeavyUAV", 5.0f, 5.0f));
            modes.Add(new PerceptionModality("SmallUAV", 4.5f, 4.5f));
            soaConfig.defaultClassifierModalities.Add("RedDismount", modes);

            // Red Truck
            modes = new List <PerceptionModality>();
            modes.Add(new PerceptionModality("BluePolice", 5.0f, 5.0f));
            modes.Add(new PerceptionModality("HeavyUAV", 5.0f, 5.0f));
            modes.Add(new PerceptionModality("SmallUAV", 4.5f, 4.5f));
            soaConfig.defaultClassifierModalities.Add("RedTruck", modes);

            // Neutral Dismount
            modes = new List <PerceptionModality>();
            soaConfig.defaultClassifierModalities.Add("NeutralDismount", modes);

            // Neutral Truck
            modes = new List <PerceptionModality>();
            soaConfig.defaultClassifierModalities.Add("NeutralTruck", modes);

            // Blue Police
            modes = new List <PerceptionModality>();
            modes.Add(new PerceptionModality("RedDismount", 0.5f, 0.5f));
            modes.Add(new PerceptionModality("RedTruck", 0.5f, 0.5f));
            modes.Add(new PerceptionModality("NeutralDismount", 0.5f, 0.5f));
            modes.Add(new PerceptionModality("NeutralTruck", 0.5f, 0.5f));
            soaConfig.defaultClassifierModalities.Add("BluePolice", modes);

            // Heavy UAV
            modes = new List <PerceptionModality>();
            modes.Add(new PerceptionModality("RedDismount", 0.5f, 0.5f));
            modes.Add(new PerceptionModality("RedTruck", 0.5f, 0.5f));
            modes.Add(new PerceptionModality("NeutralDismount", 0.5f, 0.5f));
            modes.Add(new PerceptionModality("NeutralTruck", 0.5f, 0.5f));
            soaConfig.defaultClassifierModalities.Add("HeavyUAV", modes);

            // Small UAV
            modes = new List <PerceptionModality>();
            modes.Add(new PerceptionModality("RedDismount", 0.5f, 5.0f));
            modes.Add(new PerceptionModality("RedTruck", 0.5f, 7.0f));
            modes.Add(new PerceptionModality("NeutralDismount", 0.5f, 5.0f));
            modes.Add(new PerceptionModality("NeutralTruck", 0.5f, 7.0f));
            soaConfig.defaultClassifierModalities.Add("SmallUAV", modes);

            // Blue Balloon
            modes = new List <PerceptionModality>();
            soaConfig.defaultClassifierModalities.Add("BlueBalloon", modes);
        }
        //public void SetCommsDefaults(SoaConfig soaConfig, float min, float max, int trial)
        public void SetCommsDefaults(SoaConfig soaConfig)
        {
            float randDist = experiment.GetCommsRange();

            soaConfig.defaultCommsRanges["BlueBase"]    = randDist;
            soaConfig.defaultCommsRanges["RedDismount"] = 5.0f;
            soaConfig.defaultCommsRanges["RedTruck"]    = 5.0f;
            soaConfig.defaultCommsRanges["BluePolice"]  = randDist;
            soaConfig.defaultCommsRanges["HeavyUAV"]    = randDist;
            soaConfig.defaultCommsRanges["SmallUAV"]    = randDist;
        }
        private static void PopulateNetwork(XmlDocument xmlDoc, XmlNode configNode, SoaConfig soaConfig)
        {
            // Create "Network" node and append to configNode
            XmlNode node = xmlDoc.CreateElement("Network");

            configNode.AppendChild(node);

            // Add attributes
            AddAttribute(xmlDoc, node, "redRoom", soaConfig.networkRedRoom);
            AddAttribute(xmlDoc, node, "blueRoom", soaConfig.networkBlueRoom);
        }
        private static void PopulateSites(XmlDocument xmlDoc, XmlNode configNode, SoaConfig soaConfig)
        {
            // Create "Sites" node and append to configNode
            XmlNode sitesNode = xmlDoc.CreateElement("Sites");

            configNode.AppendChild(sitesNode);

            // Make a node for each site
            XmlNode node;

            foreach (SiteConfig siteConfig in soaConfig.sites)
            {
                switch (siteConfig.GetConfigType())
                {
                case SiteConfig.ConfigType.BLUE_BASE:
                    node = xmlDoc.CreateElement("BlueBase");
                    sitesNode.AppendChild(node);
                    AddAttribute(xmlDoc, node, "name", siteConfig.name);
                    AddAttribute(xmlDoc, node, "x_km", siteConfig.x_km.ToString());
                    AddAttribute(xmlDoc, node, "z_km", siteConfig.z_km.ToString());
                    AddOptionalAttribute(xmlDoc, node, "commsRange_km", ((BlueBaseConfig)siteConfig).commsRange_km);
                    break;

                case SiteConfig.ConfigType.RED_BASE:
                    node = xmlDoc.CreateElement("RedBase");
                    sitesNode.AppendChild(node);
                    AddAttribute(xmlDoc, node, "name", siteConfig.name);
                    AddAttribute(xmlDoc, node, "x_km", siteConfig.x_km.ToString());
                    AddAttribute(xmlDoc, node, "z_km", siteConfig.z_km.ToString());
                    break;

                case SiteConfig.ConfigType.NGO_SITE:
                    node = xmlDoc.CreateElement("NGOSite");
                    sitesNode.AppendChild(node);
                    AddAttribute(xmlDoc, node, "name", siteConfig.name);
                    AddAttribute(xmlDoc, node, "x_km", siteConfig.x_km.ToString());
                    AddAttribute(xmlDoc, node, "z_km", siteConfig.z_km.ToString());
                    break;

                case SiteConfig.ConfigType.VILLAGE:
                    node = xmlDoc.CreateElement("Village");
                    sitesNode.AppendChild(node);
                    AddAttribute(xmlDoc, node, "name", siteConfig.name);
                    AddAttribute(xmlDoc, node, "x_km", siteConfig.x_km.ToString());
                    AddAttribute(xmlDoc, node, "z_km", siteConfig.z_km.ToString());
                    break;

                default:
                    Log.error("SoaConfigXMLWriter::PopulateSites(): Unrecognized config type " + siteConfig.GetConfigType() + " in soaConfig.sites");
                    break;
                }
            }
        }
        private static void PopulateLogger(XmlDocument xmlDoc, XmlNode configNode, SoaConfig soaConfig)
        {
            // Create "Logger" node and append to configNode
            XmlNode node = xmlDoc.CreateElement("Logger");

            configNode.AppendChild(node);

            // Add attributes
            AddAttribute(xmlDoc, node, "outputFile", soaConfig.loggerOutputFile);
            AddAttribute(xmlDoc, node, "enableLogToFile", soaConfig.enableLogToFile.ToString());
            AddAttribute(xmlDoc, node, "enableLogEventsToFile", soaConfig.enableLogEventsToFile.ToString());
            AddAttribute(xmlDoc, node, "enableLogToUnityConsole", soaConfig.enableLogToUnityConsole.ToString());
        }
 // Fuel default configuration category parsing
 private static void ParseFuelDefaults(XmlNode node, SoaConfig soaConfig)
 {
     // Pull attributes directly from the node
     try
     {
         soaConfig.defaultHeavyUAVFuelTankSize_s = GetFloatAttribute(node, "heavyUAVFuelTankSize_s", 10000);
         soaConfig.defaultSmallUAVFuelTankSize_s = GetFloatAttribute(node, "smallUAVFuelTankSize_s", 40000);
     }
     catch (Exception)
     {
         Debug.LogError("SoaConfigXMLReader::ParseFuelDefaults(): Error parsing " + node.Name);
     }
 }
        /********************************************************************************************
        *                               CATEGORY PARSING FUNCTIONS                                 *
        ********************************************************************************************/

        // Network configuration category parsing
        private static void ParseNetwork(XmlNode node, SoaConfig soaConfig)
        {
            // Pull attributes directly from the node
            try
            {
                soaConfig.networkRedRoom  = GetStringAttribute(node, "redRoom", "soa-default-red");
                soaConfig.networkBlueRoom = GetStringAttribute(node, "blueRoom", "soa-default-blue");
            }
            catch (Exception)
            {
                Debug.LogError("SoaConfigXMLReader::ParseNetwork(): Error parsing " + node.Name);
            }
        }
 // Storage default configuration category parsing
 private static void ParseStorageDefaults(XmlNode node, SoaConfig soaConfig)
 {
     // Pull attributes directly from the node
     try
     {
         soaConfig.defaultHeavyUAVNumStorageSlots    = GetIntAttribute(node, "heavyUAVNumStorageSlots", 1);
         soaConfig.defaultRedDismountNumStorageSlots = GetIntAttribute(node, "redDismountNumStorageSlots", 1);
         soaConfig.defaultRedTruckNumStorageSlots    = GetIntAttribute(node, "redTruckNumStorageSlots", 1);
     }
     catch (Exception)
     {
         Debug.LogError("SoaConfigXMLReader::ParseStorageDefaults(): Error parsing " + node.Name);
     }
 }
        public static void Write(SoaConfig soaConfig, string xmlFilename)
        {
            // Create new XML document
            XmlDocument xmlDoc = new XmlDocument();

            // Create "SoaConfig" node
            XmlNode configNode = xmlDoc.CreateElement("SoaConfig");

            xmlDoc.AppendChild(configNode);

            // Populate "Network" node
            PopulateNetwork(xmlDoc, configNode, soaConfig);

            // Populate "Logger" node
            PopulateLogger(xmlDoc, configNode, soaConfig);

            // Populate "Simulation" node
            PopulateSimulation(xmlDoc, configNode, soaConfig);

            // Populate "FuelDefaults" node
            PopulateFuelDefaults(xmlDoc, configNode, soaConfig);

            // Populate "StorageDefaults" node
            PopulateStorageDefaults(xmlDoc, configNode, soaConfig);

            // Populate "SensorDefaults" node
            PopulateSensorDefaults(xmlDoc, configNode, soaConfig);

            // Populate "ClassifierDefaults" node
            PopulateClassifierDefaults(xmlDoc, configNode, soaConfig);

            // Populate "CommsDefaults" node
            PopulateCommsDefaults(xmlDoc, configNode, soaConfig);

            // Populate "JammerDefaults" node
            PopulateJammerDefaults(xmlDoc, configNode, soaConfig);

            // Populate "Sites" node
            PopulateSites(xmlDoc, configNode, soaConfig);

            // Populate "Local" node
            PopulateLocal(xmlDoc, configNode, soaConfig);

            // Populate "Remote" node
            PopulateRemote(xmlDoc, configNode, soaConfig);

            // Write to file
            xmlDoc.Save(xmlFilename);
        }
 // Logger configuration category parsing
 private static void ParseLogger(XmlNode node, SoaConfig soaConfig)
 {
     // Pull attributes directly from the node
     try
     {
         soaConfig.loggerOutputFile        = GetStringAttribute(node, "outputFile", "SoaSimOutput.xml");
         soaConfig.enableLogToFile         = GetBooleanAttribute(node, "enableLogToFile", true);
         soaConfig.enableLogEventsToFile   = GetBooleanAttribute(node, "enableLogEventsToFile", true);
         soaConfig.enableLogToUnityConsole = GetBooleanAttribute(node, "enableLogToUnityConsole", true);
     }
     catch (Exception)
     {
         Debug.LogError("SoaConfigXMLReader::ParseLogger(): Error parsing " + node.Name);
     }
 }
 // Simulation configuration category parsing
 private static void ParseSimulation(XmlNode node, SoaConfig soaConfig)
 {
     // Pull attributes directly from the node
     try
     {
         soaConfig.simulationRandomSeed     = GetIntAttribute(node, "simulationRandomSeed", 0);
         soaConfig.gameDurationHr           = GetFloatAttribute(node, "gameDurationHr", 15.0f);
         soaConfig.probRedDismountHasWeapon = GetFloatAttribute(node, "probRedDismountHasWeapon", 0.5f);
         soaConfig.probRedTruckHasWeapon    = GetFloatAttribute(node, "probRedTruckHasWeapon", 0.5f);
         soaConfig.probRedTruckHasJammer    = GetFloatAttribute(node, "probRedTruckHasJammer", 0.5f);
     }
     catch (Exception)
     {
         Debug.LogError("SoaConfigXMLReader::ParseSimulation(): Error parsing " + node.Name);
     }
 }
Exemple #17
0
        public void GenerateConfigFiles()
        {
            for (int run = 1; run <= numMCRuns; run++)
            {
                experiment.StartNewRun();
                simulationRandomSeed = rand.Next(); //trials should share the random seed

                for (int trial = 1; trial <= numTrialsPerRun; trial++)
                {
                    experiment.StartNewTrial();

                    SoaConfig config = CreateTrial(trial);
                    WriteConfig(run, trial, config);
                }
            }
        }
        private static void PopulateLocal(XmlDocument xmlDoc, XmlNode configNode, SoaConfig soaConfig)
        {
            // Create "Local" node and append to configNode
            XmlNode node = xmlDoc.CreateElement("Local");

            configNode.AppendChild(node);

            // Go through each local platform and add children to "Local" node
            foreach (PlatformConfig p in soaConfig.localPlatforms)
            {
                switch (p.GetConfigType())
                {
                case PlatformConfig.ConfigType.RED_DISMOUNT:
                    PopulateRedDismount(xmlDoc, node, (RedDismountConfig)p);
                    break;

                case PlatformConfig.ConfigType.RED_TRUCK:
                    PopulateRedTruck(xmlDoc, node, (RedTruckConfig)p);
                    break;

                case PlatformConfig.ConfigType.NEUTRAL_DISMOUNT:
                    PopulateNeutralDismount(xmlDoc, node, (NeutralDismountConfig)p);
                    break;

                case PlatformConfig.ConfigType.NEUTRAL_TRUCK:
                    PopulateNeutralTruck(xmlDoc, node, (NeutralTruckConfig)p);
                    break;

                case PlatformConfig.ConfigType.BLUE_POLICE:
                    PopulateBluePolice(xmlDoc, node, (BluePoliceConfig)p);
                    break;

                default:
                    Log.error("SoaConfigXMLWriter::PopulateLocal(): Unrecognized config type " + p.GetConfigType() + " in soaConfig.localPlatforms");
                    break;
                }
            }
        }
 public void SetJammerDefaults(SoaConfig soaConfig)
 {
     soaConfig.defaultJammerRanges["RedTruck"] = 2.0f;
 }
        private static void PopulateJammerDefaults(XmlDocument xmlDoc, XmlNode configNode, SoaConfig soaConfig)
        {
            // Create JammerDefaults node
            XmlNode jammerDefaultsNode = xmlDoc.CreateElement("JammerDefaults");

            configNode.AppendChild(jammerDefaultsNode);

            // Make an entry for each key
            XmlNode platformNode;

            foreach (string platformName in soaConfig.defaultJammerRanges.Keys)
            {
                // Create and attach node
                platformNode = xmlDoc.CreateElement("Node");
                jammerDefaultsNode.AppendChild(platformNode);

                // Add attributes
                AddAttribute(xmlDoc, platformNode, "tag", platformName);
                AddAttribute(xmlDoc, platformNode, "jammerRange_km", soaConfig.defaultJammerRanges[platformName].ToString());
            }
        }
        public static SoaConfig Parse(string xmlFilename)
        {
            // Initialize SoaConfig object to hold results
            SoaConfig soaConfig = new SoaConfig();

            // Read in the XML document
            XmlDocument xmlDoc = new XmlDocument();

            try
            {
                xmlDoc.Load(xmlFilename);
            }
            catch (Exception e)
            {
                // Handle error if not found
                Debug.LogError("SoaConfigXMLReader::Parse(): Could not load " + xmlFilename + " because " + e.Message);
                return(null);
            }

            // Find the "SoaConfig" category
            XmlNode configNode = null;

            foreach (XmlNode c in xmlDoc.ChildNodes)
            {
                if (c.Name == "SoaConfig")
                {
                    configNode = c;
                    break;
                }
            }

            // Check if we actually found it
            if (configNode == null)
            {
                // Handle error if not found
                Debug.LogError("SoaConfigXMLReader::Parse(): Could not find \"SoaConfig\" node");
                return(null);
            }

            // Parse network and simulation setup first
            foreach (XmlNode c in configNode.ChildNodes)
            {
                // Parse differently depending on which category we are in
                switch (c.Name)
                {
                case "Network":
                    // Network configuration
                    ParseNetwork(c, soaConfig);
                    break;

                case "Logger":
                    // Logger configuration
                    ParseLogger(c, soaConfig);
                    break;

                case "Simulation":
                    // Simulation configuration
                    ParseSimulation(c, soaConfig);
                    break;

                case "FuelDefaults":
                    // Fuel default configuration
                    ParseFuelDefaults(c, soaConfig);
                    break;

                case "StorageDefaults":
                    // Storage default configuration
                    ParseStorageDefaults(c, soaConfig);
                    break;

                case "SensorDefaults":
                    // Sensor default configuration
                    ParseBeamwidthDefaults(c, soaConfig.defaultSensorBeamwidths);
                    ParsePerceptionDefaults(c, soaConfig.defaultSensorModalities);
                    break;

                case "ClassifierDefaults":
                    // Classifier default configuration
                    ParsePerceptionDefaults(c, soaConfig.defaultClassifierModalities);
                    break;

                case "CommsDefaults":
                    // Comms default configuration
                    ParseCommsDefaults(c, soaConfig.defaultCommsRanges);
                    break;

                case "JammerDefaults":
                    // Jammer default configuration
                    ParseJammerDefaults(c, soaConfig.defaultJammerRanges);
                    break;
                }
            }

            // Then look at sites, local, and remote platforms whose defaults may
            // use information from previously parsed categories
            // (Note: This step should be done last)
            foreach (XmlNode c in configNode.ChildNodes)
            {
                // Parse differently depending on which category we are in
                switch (c.Name)
                {
                case "Sites":
                    // Sites configuration
                    ParseSites(c, soaConfig);
                    break;

                case "Local":
                    // Local platforms
                    ParseLocal(c, soaConfig);
                    break;

                case "Remote":
                    // Remote platforms
                    ParseRemote(c, soaConfig);
                    break;
                }
            }

            // Return result
            return(soaConfig);
        }
        private static void PopulateSensorDefaults(XmlDocument xmlDoc, XmlNode configNode, SoaConfig soaConfig)
        {
            // Create SensorDefaults node
            XmlNode sensorDefaultsNode = xmlDoc.CreateElement("SensorDefaults");

            configNode.AppendChild(sensorDefaultsNode);

            // Make an entry for each key
            XmlNode platformNode;

            foreach (string platformName in soaConfig.defaultSensorModalities.Keys)
            {
                // Create node and add to perception group
                platformNode = xmlDoc.CreateElement(platformName);
                sensorDefaultsNode.AppendChild(platformNode);

                // Add beamwidth_deg attribute only for UAVs and Balloons and for sensor only
                switch (platformName)
                {
                case "HeavyUAV":
                case "SmallUAV":
                case "BlueBalloon":
                    if (soaConfig.defaultSensorBeamwidths.ContainsKey(platformName))
                    {
                        AddAttribute(xmlDoc, platformNode, "beamwidth_deg", soaConfig.defaultSensorBeamwidths[platformName].ToString());
                    }
                    break;
                }

                // Add modes
                PopulatePerceptionModes(xmlDoc, platformNode, soaConfig.defaultSensorModalities[platformName]);
            }
        }
        private static void PopulateClassifierDefaults(XmlDocument xmlDoc, XmlNode configNode, SoaConfig soaConfig)
        {
            // Create ClassifierDefaults node
            XmlNode classifierDefaultsNode = xmlDoc.CreateElement("ClassifierDefaults");

            configNode.AppendChild(classifierDefaultsNode);

            // Make an entry for each key
            XmlNode platformNode;

            foreach (string platformName in soaConfig.defaultClassifierModalities.Keys)
            {
                // Create node and add to perception group
                platformNode = xmlDoc.CreateElement(platformName);
                classifierDefaultsNode.AppendChild(platformNode);

                // Add modes
                PopulatePerceptionModes(xmlDoc, platformNode, soaConfig.defaultClassifierModalities[platformName]);
            }
        }
        private static void PopulateFuelDefaults(XmlDocument xmlDoc, XmlNode configNode, SoaConfig soaConfig)
        {
            // Create "FuelDefaults" node and append to configNode
            XmlNode node = xmlDoc.CreateElement("FuelDefaults");

            configNode.AppendChild(node);

            // Add attributes
            AddAttribute(xmlDoc, node, "heavyUAVFuelTankSize_s", soaConfig.defaultHeavyUAVFuelTankSize_s.ToString());
            AddAttribute(xmlDoc, node, "smallUAVFuelTankSize_s", soaConfig.defaultSmallUAVFuelTankSize_s.ToString());
        }
        private static void PopulateStorageDefaults(XmlDocument xmlDoc, XmlNode configNode, SoaConfig soaConfig)
        {
            // Create "StorageDefaults" node and append to configNode
            XmlNode node = xmlDoc.CreateElement("StorageDefaults");

            configNode.AppendChild(node);

            // Add attributes
            AddAttribute(xmlDoc, node, "heavyUAVNumStorageSlots", soaConfig.defaultHeavyUAVNumStorageSlots.ToString());
            AddAttribute(xmlDoc, node, "redDismountNumStorageSlots", soaConfig.defaultRedDismountNumStorageSlots.ToString());
            AddAttribute(xmlDoc, node, "redTruckNumStorageSlots", soaConfig.defaultRedTruckNumStorageSlots.ToString());
        }
        private static void PopulateSimulation(XmlDocument xmlDoc, XmlNode configNode, SoaConfig soaConfig)
        {
            // Create "Simulation" node and append to configNode
            XmlNode node = xmlDoc.CreateElement("Simulation");

            configNode.AppendChild(node);

            // Add attributes
            AddAttribute(xmlDoc, node, "simulationRandomSeed", soaConfig.simulationRandomSeed.ToString());
            AddAttribute(xmlDoc, node, "gameDurationHr", soaConfig.gameDurationHr.ToString());
            AddAttribute(xmlDoc, node, "probRedDismountHasWeapon", soaConfig.probRedDismountHasWeapon.ToString());
            AddAttribute(xmlDoc, node, "probRedTruckHasWeapon", soaConfig.probRedTruckHasWeapon.ToString());
            AddAttribute(xmlDoc, node, "probRedTruckHasJammer", soaConfig.probRedTruckHasJammer.ToString());
            AddAttribute(xmlDoc, node, "controlUpdateRate_s", soaConfig.controlUpdateRate_s.ToString());
            AddAttribute(xmlDoc, node, "predRedMovement", soaConfig.predRedMovement.ToString());
        }
        // Site configuration category parsing
        private static void ParseSites(XmlNode node, SoaConfig soaConfig)
        {
            SiteConfig newConfig = null; // Dummy value
            // Go through each child node
            bool newConfigValid;

            foreach (XmlNode c in node.ChildNodes)
            {
                newConfigValid = true;

                try
                {
                    switch (c.Name)
                    {
                    case "BlueBase":
                    {
                        newConfig = new BlueBaseConfig(
                            GetFloatAttribute(c, "x_km", 0),
                            GetFloatAttribute(c, "z_km", 0),
                            GetStringAttribute(c, "name", null),
                            GetOptionalFloatAttribute(c, "commsRange_km")
                            );
                    }
                    break;

                    case "RedBase":
                    {
                        newConfig = new RedBaseConfig(
                            GetFloatAttribute(c, "x_km", 0),
                            GetFloatAttribute(c, "z_km", 0),
                            GetStringAttribute(c, "name", null)
                            );
                    }
                    break;

                    case "NGOSite":
                    {
                        newConfig = new NGOSiteConfig(
                            GetFloatAttribute(c, "x_km", 0),
                            GetFloatAttribute(c, "z_km", 0),
                            GetStringAttribute(c, "name", null)
                            );
                    }
                    break;

                    case "Village":
                    {
                        newConfig = new VillageConfig(
                            GetFloatAttribute(c, "x_km", 0),
                            GetFloatAttribute(c, "z_km", 0),
                            GetStringAttribute(c, "name", null)
                            );
                    }
                    break;

                    default:
                        newConfigValid = false;
                        if (c.Name != "#comment")
                        {
                            Debug.LogWarning("SoaConfigXMLReader::ParseSites(): Unrecognized node " + c.Name);
                        }
                        break;
                    }
                }
                catch (Exception)
                {
                    Debug.LogError("SoaConfigXMLReader::ParseSites(): Error parsing " + c.Name);
                } // End try-catch

                // Add to list of sites if valid
                if (newConfigValid)
                {
                    soaConfig.sites.Add(newConfig);
                }
            } // End foreach
        }
        // Local platform category parsing
        private static void ParseLocal(XmlNode node, SoaConfig soaConfig)
        {
            // Go through each child node
            PlatformConfig newConfig = new BluePoliceConfig(0.0f, 0.0f, 0.0f, new Optional <int>(), new Optional <float>(), new Optional <float>()); // Dummy value
            bool           newConfigValid;

            foreach (XmlNode c in node.ChildNodes)
            {
                newConfigValid = true;

                try
                {
                    switch (c.Name)
                    {
                    case "RedDismount":
                    {
                        newConfig = new RedDismountConfig(
                            GetFloatAttribute(c, "x_km", 0),
                            0,         // No y_km field for land unit
                            GetFloatAttribute(c, "z_km", 0),
                            GetOptionalIntAttribute(c, "id"),
                            GetOptionalFloatAttribute(c, "sensorBeamwidth_deg"),
                            GetOptionalStringAttribute(c, "initialWaypoint"),
                            GetOptionalBooleanAttribute(c, "hasWeapon"),
                            GetOptionalFloatAttribute(c, "commsRange_km"),
                            GetOptionalIntAttribute(c, "numStorageSlots")
                            );
                    }
                    break;

                    case "RedTruck":
                    {
                        newConfig = new RedTruckConfig(
                            GetFloatAttribute(c, "x_km", 0),
                            0,         // No y_km field for land unit
                            GetFloatAttribute(c, "z_km", 0),
                            GetOptionalIntAttribute(c, "id"),
                            GetOptionalFloatAttribute(c, "sensorBeamwidth_deg"),
                            GetOptionalStringAttribute(c, "initialWaypoint"),
                            GetOptionalBooleanAttribute(c, "hasWeapon"),
                            GetOptionalBooleanAttribute(c, "hasJammer"),
                            GetOptionalFloatAttribute(c, "commsRange_km"),
                            GetOptionalFloatAttribute(c, "jammerRange_km"),
                            GetOptionalIntAttribute(c, "numStorageSlots")
                            );
                    }
                    break;

                    case "NeutralDismount":
                    {
                        newConfig = new NeutralDismountConfig(
                            GetFloatAttribute(c, "x_km", 0),
                            0,         // No y_km field for land unit
                            GetFloatAttribute(c, "z_km", 0),
                            GetOptionalIntAttribute(c, "id"),
                            GetOptionalFloatAttribute(c, "sensorBeamwidth_deg")
                            );
                    }
                    break;

                    case "NeutralTruck":
                    {
                        newConfig = new NeutralTruckConfig(
                            GetFloatAttribute(c, "x_km", 0),
                            0,         // No y_km field for land unit
                            GetFloatAttribute(c, "z_km", 0),
                            GetOptionalIntAttribute(c, "id"),
                            GetOptionalFloatAttribute(c, "sensorBeamwidth_deg")
                            );
                    }
                    break;

                    case "BluePolice":
                    {
                        newConfig = new BluePoliceConfig(
                            GetFloatAttribute(c, "x_km", 0),
                            0,         // No y_km field for land unit
                            GetFloatAttribute(c, "z_km", 0),
                            GetOptionalIntAttribute(c, "id"),
                            GetOptionalFloatAttribute(c, "sensorBeamwidth_deg"),
                            GetOptionalFloatAttribute(c, "commsRange_km")
                            );
                    }
                    break;

                    default:
                        newConfigValid = false;
                        if (c.Name != "#comment")
                        {
                            Debug.LogWarning("SoaConfigXMLReader::ParseLocal(): Unrecognized node " + c.Name);
                        }
                        break;
                    }
                }
                catch (Exception)
                {
                    Debug.LogError("SoaConfigXMLReader::ParseLocal(): Error parsing " + c.Name);
                } // End try-catch

                // Handle and add the new config if it is valid
                if (newConfigValid)
                {
                    // Parse any sensor/classifier override modalities specified
                    foreach (XmlNode g in c.ChildNodes)
                    {
                        switch (g.Name)
                        {
                        case "Sensor":
                            newConfig.SetSensorModalities(ParseModalities(g));
                            break;

                        case "Classifier":
                            newConfig.SetClassifierModalities(ParseModalities(g));
                            break;
                        }
                    }

                    // Add to list of local platforms
                    soaConfig.localPlatforms.Add(newConfig);
                } // End if new config valid
            }     // End foreach
        }
        // Remote platform category parsing
        private static void ParseRemote(XmlNode node, SoaConfig soaConfig)
        {
            PlatformConfig newConfig = null; // Dummy value
            bool           newConfigValid;

            // Go through each child node
            foreach (XmlNode c in node.ChildNodes)
            {
                newConfigValid = true;

                try
                {
                    switch (c.Name)
                    {
                    case "HeavyUAV":
                    {
                        newConfig = new HeavyUAVConfig(
                            GetFloatAttribute(c, "x_km", 0),
                            GetFloatAttribute(c, "y_km", 0),
                            GetFloatAttribute(c, "z_km", 0),
                            GetIntAttribute(c, "id", -1),         // Default -1 means runtime determined id field
                            GetOptionalFloatAttribute(c, "sensorBeamwidth_deg"),
                            GetOptionalFloatAttribute(c, "commsRange_km"),
                            GetOptionalFloatAttribute(c, "fuelTankSize_s"),
                            GetOptionalIntAttribute(c, "numStorageSlots")
                            );
                    }
                    break;

                    case "SmallUAV":
                    {
                        newConfig = new SmallUAVConfig(
                            GetFloatAttribute(c, "x_km", 0),
                            GetFloatAttribute(c, "y_km", 0),
                            GetFloatAttribute(c, "z_km", 0),
                            GetIntAttribute(c, "id", -1),         // Default -1 means runtime determined id field
                            GetOptionalFloatAttribute(c, "sensorBeamwidth_deg"),
                            GetOptionalFloatAttribute(c, "commsRange_km"),
                            GetOptionalFloatAttribute(c, "fuelTankSize_s")
                            );
                    }
                    break;

                    case "BlueBalloon":
                    {
                        // Get list of waypoints
                        List <PrimitivePair <float, float> > waypoints_km = new List <PrimitivePair <float, float> >();
                        foreach (XmlNode g in c.ChildNodes)
                        {
                            switch (g.Name)
                            {
                            case "Waypoint":
                                waypoints_km.Add(new PrimitivePair <float, float>(GetFloatAttribute(g, "x_km", 0), GetFloatAttribute(g, "z_km", 0)));
                                break;
                            }
                        }

                        // Create a Blue Balloon config
                        newConfig = new BlueBalloonConfig(
                            GetIntAttribute(c, "id", -1),         // Default -1 means runtime determined id field
                            GetOptionalFloatAttribute(c, "sensorBeamwidth_deg"),
                            waypoints_km,
                            GetBooleanAttribute(c, "teleportLoop", true)
                            );
                    }
                    break;

                    default:
                        newConfigValid = false;
                        if (c.Name != "#comment")
                        {
                            Debug.LogWarning("SoaConfigXMLReader::ParseRemote(): Unrecognized node " + c.Name);
                        }
                        break;
                    }
                }
                catch (Exception)
                {
                    Debug.LogError("SoaConfigXMLReader::ParseRemote(): Error parsing " + c.Name);
                } // End try-catch

                // Handle and add the new config if it is valid
                if (newConfigValid)
                {
                    // Parse any sensor/classifier override modalities specified
                    foreach (XmlNode g in c.ChildNodes)
                    {
                        switch (g.Name)
                        {
                        case "Sensor":
                            newConfig.SetSensorModalities(ParseModalities(g));
                            break;

                        case "Classifier":
                            newConfig.SetClassifierModalities(ParseModalities(g));
                            break;
                        }
                    }

                    // Add to list of remote platforms
                    soaConfig.remotePlatforms.Add(newConfig);
                } // End if new config valid
            }     // End foreach
        }
        public void GenerateConfigFiles()
        {
            // Find out trial number formatting
            int    numTrialDigits = numMCTrials.ToString().Length;
            string toStringFormat = "D" + numTrialDigits.ToString();

            // Generate each trial
            SoaConfig soaConfig;
            List <PrimitiveTriple <float, float, float> > randomizedPositions;

            for (int trial = 1; trial <= numMCTrials; trial++)
            {
                // Status message
                Log.debug("Generating config file " + soaConfigFileHeader + trial.ToString(toStringFormat) + ".xml");

                // Initialize remote platform ID assignment
                availableRemoteID = remoteStartID;

                // Create a new SoaConfig object
                soaConfig = new SoaConfig();

                // Populate network
                soaConfig.networkRedRoom  = networkRedRoomHeader + trial.ToString(toStringFormat);
                soaConfig.networkBlueRoom = networkBlueRoomHeader + trial.ToString(toStringFormat);

                // Logger configuration
                soaConfig.loggerOutputFile        = soaLoggerFileHeader + trial.ToString(toStringFormat) + ".xml";
                soaConfig.enableLogToFile         = true;
                soaConfig.enableLogEventsToFile   = logEvents;
                soaConfig.enableLogToUnityConsole = logToUnityConsole;

                // Simulation configuration
                soaConfig.simulationRandomSeed     = simulationRandomSeed;
                soaConfig.gameDurationHr           = gameDurationHr;
                soaConfig.probRedDismountHasWeapon = probRedDismountHasWeapon;
                soaConfig.probRedTruckHasWeapon    = probRedTruckHasWeapon;
                soaConfig.probRedTruckHasJammer    = probRedTruckHasJammer;

                // Populate fuel defaults
                soaConfig.defaultSmallUAVFuelTankSize_s = defaultSmallUAVFuelTankSize_s;
                soaConfig.defaultHeavyUAVFuelTankSize_s = defaultHeavyUAVFuelTankSize_s;

                // Populate storage defaults
                soaConfig.defaultHeavyUAVNumStorageSlots    = defaultHeavyUAVStorageSlots;
                soaConfig.defaultRedDismountNumStorageSlots = defaultRedDismountStorageSlots;
                soaConfig.defaultRedTruckNumStorageSlots    = defaultRedTruckStorageSlots;

                // Set sensor and classifier defaults
                SetSensorDefaults(soaConfig);
                SetClassifierDefaults(soaConfig);

                // Set comms and jammer defaults
                SetCommsDefaults(soaConfig);
                SetJammerDefaults(soaConfig);

                // Initialize and set site locations
                SetSiteLocations(soaConfig);

                // Initialize platform laydown
                InitializeLocalLaydown();
                InitializeRemoteLaydown();

                // Local units: Red Dismount
                randomizedPositions = redDismountLaydown.Generate(gridMath, rand);
                for (int i = 0; i < randomizedPositions.Count; i++)
                {
                    soaConfig.localPlatforms.Add(new RedDismountConfig(
                                                     randomizedPositions[i].first,  // x
                                                     randomizedPositions[i].second, // y
                                                     randomizedPositions[i].third,  // z
                                                     new Optional <int>(),          // id
                                                     new Optional <float>(),        // sensorBeamwidth_deg
                                                     new Optional <string>(),       // initialWaypoint
                                                     new Optional <bool>(),         // hasWeapon
                                                     new Optional <float>(),        // commsRange_km
                                                     new Optional <int>()           // numStorageSlots
                                                     ));
                }

                // Local units: Red Truck
                randomizedPositions = redTruckLaydown.Generate(gridMath, rand);
                for (int i = 0; i < randomizedPositions.Count; i++)
                {
                    soaConfig.localPlatforms.Add(new RedTruckConfig(
                                                     randomizedPositions[i].first,  // x
                                                     randomizedPositions[i].second, // y
                                                     randomizedPositions[i].third,  // z
                                                     new Optional <int>(),          // id
                                                     new Optional <float>(),        // sensorBeamwidth_deg
                                                     new Optional <string>(),       // initialWaypoint
                                                     new Optional <bool>(),         // hasWeapon
                                                     new Optional <bool>(),         // hasJammer
                                                     new Optional <float>(),        // commsRange_km
                                                     new Optional <float>(),        // jammerRange_km
                                                     new Optional <int>()           // numStorageSlots
                                                     ));
                }

                // Local units: Neutral Dismount
                randomizedPositions = neutralDismountLaydown.Generate(gridMath, rand);
                for (int i = 0; i < randomizedPositions.Count; i++)
                {
                    soaConfig.localPlatforms.Add(new NeutralDismountConfig(
                                                     randomizedPositions[i].first,  // x
                                                     randomizedPositions[i].second, // y
                                                     randomizedPositions[i].third,  // z
                                                     new Optional <int>(),          // id
                                                     new Optional <float>()         // sensorBeamwidth_deg
                                                     ));
                }

                // Local units: Neutral Truck
                randomizedPositions = neutralTruckLaydown.Generate(gridMath, rand);
                for (int i = 0; i < randomizedPositions.Count; i++)
                {
                    soaConfig.localPlatforms.Add(new NeutralTruckConfig(
                                                     randomizedPositions[i].first,  // x
                                                     randomizedPositions[i].second, // y
                                                     randomizedPositions[i].third,  // z
                                                     new Optional <int>(),          // id
                                                     new Optional <float>()         // sensorBeamwidth_deg
                                                     ));
                }

                // Local units: Blue Police
                randomizedPositions = bluePoliceLaydown.Generate(gridMath, rand);
                for (int i = 0; i < randomizedPositions.Count; i++)
                {
                    soaConfig.localPlatforms.Add(new BluePoliceConfig(
                                                     randomizedPositions[i].first,  // x
                                                     randomizedPositions[i].second, // y
                                                     randomizedPositions[i].third,  // z
                                                     new Optional <int>(),          // id
                                                     new Optional <float>(),        // sensorBeamwidth_deg
                                                     new Optional <float>()         // commsRange_km
                                                     ));
                }

                // Remote units: Heavy UAV
                randomizedPositions = heavyUAVLaydown.Generate(gridMath, rand);
                for (int i = 0; i < randomizedPositions.Count; i++)
                {
                    soaConfig.remotePlatforms.Add(new HeavyUAVConfig(
                                                      randomizedPositions[i].first,  // x
                                                      randomizedPositions[i].second, // y
                                                      randomizedPositions[i].third,  // z
                                                      availableRemoteID++,           // id
                                                      new Optional <float>(),        // sensorBeamwidth_deg
                                                      new Optional <float>(),        // commsRange_km
                                                      new Optional <float>(),        // fuelTankSize_s
                                                      new Optional <int>()           // numStorageSlots
                                                      ));
                }

                // Remote units: Small UAV
                randomizedPositions = smallUAVLaydown.Generate(gridMath, rand);
                for (int i = 0; i < randomizedPositions.Count; i++)
                {
                    soaConfig.remotePlatforms.Add(new SmallUAVConfig(
                                                      randomizedPositions[i].first,  // x
                                                      randomizedPositions[i].second, // y
                                                      randomizedPositions[i].third,  // z
                                                      availableRemoteID++,           // id
                                                      new Optional <float>(),        // sensorBeamwidth_deg
                                                      new Optional <float>(),        // commsRange_km
                                                      new Optional <float>()         // fuelTankSize_s
                                                      ));
                }

                // Remote units: Blue Balloon
                List <PrimitivePair <float, float> > balloonWaypoints = new List <PrimitivePair <float, float> >();
                balloonWaypoints.Add(new PrimitivePair <float, float>(-28, 0));
                balloonWaypoints.Add(new PrimitivePair <float, float>(29, 0));
                soaConfig.remotePlatforms.Add(new BlueBalloonConfig(
                                                  availableRemoteID++,    // id
                                                  new Optional <float>(), // sensorBeamwidth_deg
                                                  balloonWaypoints,
                                                  true
                                                  ));

                // Create output directory if it does not already exist and Write SoaConfig contents to a config file
                Directory.CreateDirectory(soaConfigOutputPath);
                SoaConfigXMLWriter.Write(soaConfig, Path.Combine(soaConfigOutputPath, soaConfigFileHeader + trial.ToString(toStringFormat) + ".xml"));
            } // End current trial
        }