static void TestAraPhone()
        {
            Endo e = new Endo(null, "endo", new Vector3D(0, 0, 0), 0);

            Module_1x2 m1 = new Module_1x2("m1");
            Module_2x2 m2 = new Module_2x2("m2");
            Module_1x2 m4 = new Module_1x2("m4");
            Module_2x2 m5 = new Module_2x2("m5");
            Module_1x2 m6 = new Module_1x2("m6");
            Module_1x2 m7 = new Module_1x2("m7");

            XmlCompound u1 = new XmlCompound(m1, "u1", new Vector3D(0, 0, 0), 0);
            u1.Parse(XElement.Load("Box.xml"));
            u1.Transformations.Add(new TTranslate(20, 3, 3));
            m5.Add(u1);

            //e.AddModule(1, m1);
            //e.AddModule(3, m2);
            //e.AddModule(4, m4);
            e.AddModule(5, m5);
            //e.AddModule(6, m6);
            //e.AddModule(7, m7);

            // Phantom
            Compound headPhantom = new Compound("head-phantom");

            Dielectric skinMaterial = new Dielectric("skin", 50, kappa: 0.65, density: 1100);
            skinMaterial.FillColor = new Material.Color(245, 215, 205, 54);
            skinMaterial.EdgeColor = new Material.Color(255, 235, 217, 250);
            Sphere skin = new Sphere(null, skinMaterial, 11, new Vector3D(), 1);
            skin.Transformations.Add(new TScale(80, 100, 80));
            headPhantom.Add(skin);

            Dielectric boneMaterial = new Dielectric("bone", 13, kappa: 0.1, density: 2000);
            boneMaterial.FillColor = new Material.Color(227, 227, 227, 54);
            boneMaterial.EdgeColor = new Material.Color(202, 202, 202, 250);
            Sphere bone = new Sphere(null, boneMaterial, 12, new Vector3D(), 1);
            bone.Transformations.Add(new TScale(75, 95, 75));
            headPhantom.Add(bone);

            Dielectric brainMaterial = new Dielectric("brain", 60, kappa: 0.7, density: 1040);
            brainMaterial.FillColor = new Material.Color(255, 85, 127, 54);
            brainMaterial.EdgeColor = new Material.Color(71, 222, 179, 250);
            Sphere brain = new Sphere(null, brainMaterial, 13, new Vector3D(), 1);
            brain.Transformations.Add(new TScale(65, 85, 65));
            headPhantom.Add(brain);

            headPhantom.Transformations.Add(new TTranslate(33, 70, 90));

            Compound s = new Compound("space");
            s.Add(e);
            s.Add(headPhantom);

            RectilinearGrid g = new SimpleGrid_6x3();
            g.ZLines.Add(170);
            double airBox = 50;
            double maxRes = 5;
            double ratio = 1.5;

            g.AddAirbox(airBox);
            g.SmoothMesh(maxRes, ratio);

            s.Add(new SARBox("SAR", 1200e6, new Vector3D(), new Vector3D(20, 20, 20)));
            s.Add(new NF2FFBox("nf2ff",
                new Vector3D(g.XLines.First(), g.YLines.First(), g.ZLines.First()),
                new Vector3D(g.XLines.Last(), g.YLines.Last(), g.ZLines.Last())));
            s.Add(new LumpedPort(100, 1, 50.0,
                new Vector3D(-0.1, -0.1, -1.25),
                new Vector3D(+0.1, +0.1, +1.25), ENormDir.Z, true));
                
            Simulation fdtd = new Simulation();
            fdtd.Excitation = new GaussExcitation(1e9, 1.5e9);

            g.AddPML(10);

            XDocument doc = new XDocument(
                new XDeclaration("1.0", "utf-8", "yes"),
                new XComment("Test XML file for CyPhy generated openEMS simulations"),
                new XElement("openEMS",
                    fdtd.ToXElement(),
                    new XElement("ContinuousStructure",
                        new XAttribute("CoordSystem", 0),
                        s.ToXElement(),
                        g.ToXElement()
                    )
                )
            );

            doc.Save("CSXTest.xml");
        }
        static void ExportAntenna_InvertedF()
        {
            double thickness = 0.01;
            double airBox = 5.0;
            double innerResolution = 0.5;
            double outerResolution = 5.0;

            var antenna = new CSXCAD.Antenna.InvertedF_2400MHz(thickness);

            const double pcbThickness = 1.5;
            var lumpedPort = new LumpedPort(90, 1, 50, new Vector3D(0.0, 0.0, -pcbThickness), new Vector3D(0.0, 0.0, 0), ENormDir.Z, true);
            antenna.Add(lumpedPort);

            double margin = 2.0;
            double groundWidth = 5.0;
            var p1 = new Vector3D(antenna.BoundingBox.P1.x-margin, -groundWidth-margin, -pcbThickness);
            var p2 = new Vector3D(antenna.BoundingBox.P2.x+margin, antenna.BoundingBox.P2.y+margin, 0);

            var substrate = new Dielectric("pcb", 3.38, 1e-3 * 2 * Math.PI * 2.45e9 * 3.38 * Material.Eps0);
            substrate.EdgeColor = new Material.Color(10, 255, 10, 128);
            substrate.FillColor = new Material.Color(10, 255, 10, 128);
            var pcb = new CSXCAD.Box(null, substrate, 60, p1, p2);
            //antenna.Add(pcb);

            var topGround = new Metal("bottom-ground");
            topGround.EdgeColor = new Material.Color(235, 148, 7, 255);
            topGround.FillColor = topGround.EdgeColor;
            var topGroundPlane = new CSXCAD.Box(null, topGround, 100,
                new Vector3D(antenna.BoundingBox.P1.x, 0, -pcbThickness),
                new Vector3D(antenna.BoundingBox.P2.x, -groundWidth, -pcbThickness));
            antenna.Add(topGroundPlane);

            var bottomGround = new Metal("top-ground");
            bottomGround.EdgeColor = new Material.Color(235, 148, 7, 255);
            bottomGround.FillColor = bottomGround.EdgeColor;
            var topGroundPlaneLeft = new CSXCAD.Box(null, bottomGround, 100,
                new Vector3D(antenna.BoundingBox.P1.x, 0, 0),
                new Vector3D(-0.46/2-0.45, -groundWidth, 0));
            var topGroundPlaneRight = new CSXCAD.Box(null, bottomGround, 100,
                new Vector3D(0.46/2+0.45, 0, 0),
                new Vector3D(antenna.BoundingBox.P2.x, -groundWidth, 0));
            antenna.Add(topGroundPlaneLeft);
            antenna.Add(topGroundPlaneRight);

            Simulation fdtd = new Simulation();
            fdtd.Excitation = new GaussExcitation(2450e6, 500e6);

            RectilinearGrid grid = new RectilinearGrid(); ;
            grid.Add(new Vector3D(0,0,0));

            grid.SmoothMesh(innerResolution);
            grid.AddAirbox(airBox);
            grid.SmoothMesh(outerResolution);
            var nf2ff = new NF2FFBox("nf2ff",
                new Vector3D(grid.XLines.First(), grid.YLines.First(), grid.ZLines.First()),
                new Vector3D(grid.XLines.Last(), grid.YLines.Last(), grid.ZLines.Last()));
            antenna.Add(nf2ff);
            grid.AddPML(8);

            XDocument doc = new XDocument(
                new XDeclaration("1.0", "utf-8", "yes"),
                new XComment("Test XML file for CyPhy generated openEMS simulations"),
                new XElement("openEMS",
                    fdtd.ToXElement(),
                    new XElement("ContinuousStructure",
                        new XAttribute("CoordSystem", 0),
                        antenna.ToXElement(),
                        grid.ToXElement()
                    )
                )
            );

            doc.Save("InvertedF.xml");
        }
        static void ExportAntenna_Small_15x6mm()
        {
            double thickness = 0.01;
            double airBox = 5.0;
            double innerResolution = 0.5;
            double outerResolution = 5.0;

            var antenna = new CSXCAD.Antenna.Small_15x6mm_2400MHz(thickness);

            const double pcbThickness = 1.5;
            var lumpedPort = new LumpedPort(90, 1, 50, new Vector3D(0.0, 0.0, -pcbThickness), new Vector3D(0.0, 0.0, 0), ENormDir.Z, true);
            antenna.Add(lumpedPort);

            double margin = 2.0;
            double groundWidth = 5.0;
            var p1 = new Vector3D(antenna.BoundingBox.P1.x - margin, -groundWidth - margin, -pcbThickness);
            var p2 = new Vector3D(antenna.BoundingBox.P2.x + margin, antenna.BoundingBox.P2.y + margin, 0);

            double epsRel = 4.88;
            var substrate = new Dielectric("pcb", epsRel, 1e-3 * 2 * Math.PI * 2.45e9 * epsRel * Material.Eps0);
            substrate.EdgeColor = new Material.Color(10, 255, 10, 128);
            substrate.FillColor = new Material.Color(10, 255, 10, 128);
            var pcb = new CSXCAD.Box(null, substrate, 60, p1, p2);
            antenna.Add(pcb);

            var bottomGround = new Metal("bottom-ground");
            bottomGround.EdgeColor = new Material.Color(235, 148, 7, 255);
            bottomGround.FillColor = bottomGround.EdgeColor;
            var bottomGroundPlane = new CSXCAD.Box(null, bottomGround, 100,
                new Vector3D(antenna.BoundingBox.P1.x - antenna.D1, antenna.D4 / 2, -pcbThickness),
                new Vector3D(antenna.BoundingBox.P2.x + antenna.D3, -groundWidth, -pcbThickness-0.01));
            antenna.Add(bottomGroundPlane);

            var topGround = new Metal("top-ground");
            topGround.EdgeColor = new Material.Color(235, 148, 7, 255);
            topGround.FillColor = topGround.EdgeColor;
            var topGroundPlane = new CSXCAD.Box(null, topGround, 100,
                new Vector3D(antenna.BoundingBox.P1.x - antenna.D1, -antenna.D4 / 2, 0),
                new Vector3D(antenna.BoundingBox.P2.x + antenna.D3, -groundWidth, 0.01));
            antenna.Add(topGroundPlane);

            var viaMetal = new Metal("via");
            viaMetal.EdgeColor = new Material.Color(235, 148, 7, 255);
            viaMetal.FillColor = viaMetal.EdgeColor;
            var via = new Cylinder(null, viaMetal, 100,
                new Vector3D(-(antenna.W1 / 2 + antenna.D5 + antenna.W2 / 2), 0, -pcbThickness),
                new Vector3D(-(antenna.W1 / 2 + antenna.D5 + antenna.W2 / 2), 0, 0),
                0.25);
            antenna.Add(via);

            Simulation fdtd = new Simulation();
            fdtd.Excitation = new GaussExcitation(2450e6, 500e6);

            RectilinearGrid grid = new RectilinearGrid(); ;
            grid.Add(new Vector3D(0, 0, 0));
            grid.Add(pcb.P1);
            grid.Add(pcb.P2);
            /*
            foreach (var v in antenna.antennaPoly)
            {
                grid.Add(new Vector3D(v.x, v.y, 0));
            }
            */

            grid.SmoothMesh(innerResolution);
            grid.AddAirbox(airBox);
            grid.SmoothMesh(outerResolution);
            var nf2ff = new NF2FFBox("nf2ff",
                new Vector3D(grid.XLines.First(), grid.YLines.First(), grid.ZLines.First()),
                new Vector3D(grid.XLines.Last(), grid.YLines.Last(), grid.ZLines.Last()));
            antenna.Add(nf2ff);
            grid.AddPML(8);

            XDocument doc = new XDocument(
                new XDeclaration("1.0", "utf-8", "yes"),
                new XComment("Test XML file for CyPhy generated openEMS simulations"),
                new XElement("openEMS",
                    fdtd.ToXElement(),
                    new XElement("ContinuousStructure",
                        new XAttribute("CoordSystem", 0),
                        antenna.ToXElement(),
                        grid.ToXElement()
                    )
                )
            );

            doc.Save("Small_15x6mm.xml");
        }
        private XDocument BuildDipoleSarXml()
        {
            double unit = 1e-3;

            double f0 = 1e9;
            double c0 = 299792458.0;
            double lambda0 = c0 / f0;

            double fStop = 1.5e9;
            double lambdaMin = c0 / fStop;

            // Simulation engine
            Simulation fdtd = new Simulation();
            fdtd.Excitation = new GaussExcitation(0, fStop); // possible typo in Dipole_SAR.xml

            // Simulation space
            Compound s = new Compound("space");

            // Dipole antenna
            double dipoleLength = 0.46 * lambda0 / unit;

            s.Add(new Box(null, new Metal("Dipole"), 1,
                new Vector3D(0, 0, -dipoleLength / 2), new Vector3D(0, 0, dipoleLength / 2)));

            // Phantom
            Compound headPhantom = new Compound("head-phantom");

            Dielectric skinMaterial = new Dielectric("skin", 50, kappa: 0.65, density: 1100);
            skinMaterial.FillColor = new Material.Color(245, 215, 205, 250);
            skinMaterial.EdgeColor = new Material.Color(255, 235, 217, 250);
            Sphere skin = new Sphere(null, skinMaterial, 11, new Vector3D(), 1);
            skin.Transformations.Add(new TScale(80, 100, 100));
            headPhantom.Add(skin);

            Dielectric boneMaterial = new Dielectric("headbone", 13, kappa: 0.1, density: 2000);
            boneMaterial.FillColor = new Material.Color(227, 227, 227, 250);
            boneMaterial.EdgeColor = new Material.Color(202, 202, 202, 250);
            Sphere bone = new Sphere(null, boneMaterial, 12, new Vector3D(), 1);
            bone.Transformations.Add(new TScale(75, 95, 95));
            headPhantom.Add(bone);

            Dielectric brainMaterial = new Dielectric("brain", 60, kappa: 0.7, density: 1040);
            brainMaterial.FillColor = new Material.Color(255, 85, 127, 250);
            brainMaterial.EdgeColor = new Material.Color(71, 222, 179, 250);
            Sphere brain = new Sphere(null, brainMaterial, 13, new Vector3D(), 1);
            brain.Transformations.Add(new TScale(65, 85, 85));
            headPhantom.Add(brain);

            headPhantom.Transformations.Add(new TTranslate(100, 0, 0));

            s.Add(headPhantom);

            // Excitation
            double meshResAir = lambdaMin / 20 / unit;
            double meshResPhantom = 2.5;

            LumpedPort lp = new LumpedPort(100, 1, 50.0,
                new Vector3D(-0.1, -0.1, -meshResPhantom / 2),
                new Vector3D(+0.1, +0.1, +meshResPhantom / 2), ENormDir.Z, true);
            s.Add(lp);

            // Grid
            RectilinearGrid g = new RectilinearGrid();

            g.XLines.Add(0);
            g.YLines.Add(0);
            foreach (double z in new double[] { -1.0 / 3, 2.0 / 3 })
            {
                g.ZLines.Add(-dipoleLength / 2 - meshResPhantom * z);
                g.ZLines.Add(+dipoleLength / 2 + meshResPhantom * z);
            }

            foreach (Sphere sp in new Sphere[] { skin, bone, brain })
            {
                g.XLines.Add(sp.AbsoluteTransformation.Matrix[0, 3] + sp.AbsoluteTransformation.Matrix[0, 0]);
                g.XLines.Add(sp.AbsoluteTransformation.Matrix[0, 3] - sp.AbsoluteTransformation.Matrix[0, 0]);
                g.YLines.Add(sp.AbsoluteTransformation.Matrix[1, 3] + sp.AbsoluteTransformation.Matrix[1, 1]);
                g.YLines.Add(sp.AbsoluteTransformation.Matrix[1, 3] - sp.AbsoluteTransformation.Matrix[1, 1]);
                g.ZLines.Add(sp.AbsoluteTransformation.Matrix[2, 3] + sp.AbsoluteTransformation.Matrix[2, 2]);
                g.ZLines.Add(sp.AbsoluteTransformation.Matrix[2, 3] - sp.AbsoluteTransformation.Matrix[2, 2]);
            }

            g.ZLines.Add(-meshResPhantom / 2); // port
            g.ZLines.Add(+meshResPhantom / 2);

            // Mesh over dipole and phantom
            g.SmoothMesh(meshResPhantom);

            g.XLines.Add(-200);
            g.XLines.Add(250 + 100);
            g.YLines.Add(-250);
            g.YLines.Add(+250);
            g.ZLines.Add(-250);
            g.ZLines.Add(+250);

            g.SmoothMesh(meshResAir, 1.2);

            s.Add(new SARBox("SAR", f0, new Vector3D(-10, -100, -100), new Vector3D(180, 100, 100)));
            s.Add(new NF2FFBox("nf2ff",
                new Vector3D(g.XLines.First(), g.YLines.First(), g.ZLines.First()),
                new Vector3D(g.XLines.Last(), g.YLines.Last(), g.ZLines.Last()),
                lambdaMin / 15 / unit));

            g.AddPML(10);

            g.XLines.Sort();
            g.YLines.Sort();
            g.ZLines.Sort();

            // Export
            return new XDocument(
                new XDeclaration("1.0", "utf-8", "yes"),
                new XComment("Test XML file for CyPhy generated openEMS simulations"),
                new XElement("openEMS",
                    fdtd.ToXElement(),
                    new XElement("ContinuousStructure",
                        new XAttribute("CoordSystem", 0),
                        s.ToXElement(),
                        g.ToXElement()
                    )
                )
            );
        }
        private void GenerateSarSimulationInput()
        {
            // Constants
            double unit = 1e-3;
            double c0 = 299792458.0;
            double lambda0 = c0 / m_f0;
            double f_c = 500e6;
            double lambdaMin = c0 / (m_f0 + f_c);

            Compound simulationSpace = new Compound("space");
            Compound solidSpace = new Compound("solid-space");
            simulationSpace.Add(solidSpace);
            solidSpace.Add(m_endo);

            var headPhantom = new CSXCAD.Ara.HeadPhantom();
            headPhantom.Transformations.Add(new TRotateX(Math.PI / 2));
            headPhantom.Transformations.Add(new TTranslate(32.0, 80.0, -headPhantom.Width / 2 - 7.0)); // TODO: Make endo width/height accessibles
            solidSpace.Add(headPhantom);

            // Set up simulation grid, nf2ff and SAR
            Logger.WriteInfo("Constructing FDTD simulation grid...");
            double airBox = 40;
            double envResolution = Math.Round(lambdaMin / 20 / unit);
            double maxRatio = 1.5;

            RectilinearGrid grid = new BoundingGrid_6x3();

            #region openems_workaround

            // openEMS v0.0.31 seems to handle transformations on excitation (lumped port),
            // SAR and NF2FF simulation components incorrectly.
            // Applied workarounds:
            // 1. The entire design is moved so that the antenna feedpoint is in the origin
            // 2. The SAR and NF2FF boxes are added late, w/o transformations

            Vector3D dutPosition = new Vector3D(
                m_antenna.AbsoluteTransformation.X,
                m_antenna.AbsoluteTransformation.Y,
                m_antenna.AbsoluteTransformation.Z);

            solidSpace.Transformations.Add(new TTranslate(-dutPosition));

            grid.Move(-dutPosition);
            grid.Add(new Vector3D(0, 0, 0));
            grid.ZLines.Add(-(m_antenna.Parent as CSXCAD.Ara.PCB).Thickness);
            grid.Sort();
            grid.SmoothMesh(m_dutResolution, maxRatio);

            grid.Add(headPhantom.BoundingBox.P1);
            grid.Add(headPhantom.BoundingBox.P2);
            grid.SmoothMesh(m_sarResolution, maxRatio);

            grid.AddAirbox(airBox);
            grid.SmoothMesh(envResolution, maxRatio);

            simulationSpace.Add(new SARBox("SAR", m_f0,
                new Vector3D(headPhantom.XGridPoints.First(), headPhantom.YGridPoints.First(), headPhantom.ZGridPoints.First()),
                new Vector3D(headPhantom.XGridPoints.Last(), headPhantom.YGridPoints.Last(), headPhantom.ZGridPoints.Last())));
            simulationSpace.Add(new NF2FFBox("nf2ff",
                new Vector3D(grid.XLines.First(), grid.YLines.First(), grid.ZLines.First()),
                new Vector3D(grid.XLines.Last(), grid.YLines.Last(), grid.ZLines.Last()),
                lambdaMin / 15 / unit));

            #endregion

            grid.AddPML(8);

            Simulation fdtd = new Simulation();
            fdtd.Excitation = new GaussExcitation(m_f0, m_fc);

            // Export
            XDocument doc = new XDocument(
                new XDeclaration("1.0", "utf-8", "yes"),
                new XComment("CyPhy generated openEMS simulation file"),
                new XElement("openEMS",
                    fdtd.ToXElement(),
                    new XElement("ContinuousStructure",
                        new XAttribute("CoordSystem", 0),
                        simulationSpace.ToXElement(),
                        grid.ToXElement()
                    )
                )
            );

            string openEmsInput = Path.Combine(mainParameters.OutputDirectory, "openEMS_input.xml");
            doc.Save(openEmsInput);

            string nf2ffInput = Path.Combine(mainParameters.OutputDirectory, "nf2ff_input.xml");
            var nf2ff = new Postprocess.NF2FF(m_f0);
            nf2ff.ToXDocument().Save(nf2ffInput);
        }
        private void GenerateDirectivitySimulationInput()
        {
            // Constants
            double unit = 1e-3;
            double c0 = 299792458.0;
            double lambda0 = c0 / m_f0;
            double lambdaMin = c0 / (m_f0 + m_fc);

            Compound simulationSpace = new Compound("space");
            Compound solidSpace = new Compound("solid-space");
            simulationSpace.Add(solidSpace);

            Compound dut;
            if (m_excludeEndo == true)
            {
                dut = m_endo.GetModule(m_slotIndex);
            }
            else
            {
                dut = m_endo;
            }
            solidSpace.Add(dut); // modifies dut parent (!)

            // Set up simulation grid, nf2ff and SAR
            Logger.WriteInfo("Constructing FDTD simulation grid...");
            double airBox = 40;
            double maxRes = Math.Round(lambdaMin / 20 / unit);
            double maxRatio = 1.5;

            RectilinearGrid grid = new RectilinearGrid();
            grid.Add(dut.BoundingBox.P1);
            grid.Add(dut.BoundingBox.P2);

            #region openems_workaround

            // openEMS v0.0.31 seems to handle transformations on excitation (lumped port),
            // SAR and NF2FF simulation components incorrectly.
            // Applied workarounds:
            // 1. The entire design is moved so that the antenna feedpoint is in the origin
            // 2. The SAR and NF2FF boxes are added late, w/o transformations

            Vector3D antennaPosition = new Vector3D(
                m_antenna.AbsoluteTransformation.X,
                m_antenna.AbsoluteTransformation.Y,
                m_antenna.AbsoluteTransformation.Z);

            solidSpace.Transformations.Add(new TTranslate(-antennaPosition));

            grid.Move(-antennaPosition);
            grid.Add(new Vector3D(0, 0, 0));
            grid.ZLines.Add(-(m_antenna.Parent as CSXCAD.Ara.PCB).Thickness);
            grid.Sort();

            grid.SmoothMesh(m_dutResolution, maxRatio);
            grid.AddAirbox(airBox);
            grid.SmoothMesh(maxRes, maxRatio);

            simulationSpace.Add(new NF2FFBox("nf2ff",
                new Vector3D(grid.XLines.First(), grid.YLines.First(), grid.ZLines.First()),
                new Vector3D(grid.XLines.Last(), grid.YLines.Last(), grid.ZLines.Last()),
                lambdaMin / 15 / unit));
            #endregion

            grid.AddPML(8);

            Simulation fdtd = new Simulation();
            fdtd.Excitation = new GaussExcitation(m_f0, m_fc);

            // Export
            XDocument doc = new XDocument(
                new XDeclaration("1.0", "utf-8", "yes"),
                new XComment("CyPhy generated openEMS simulation file"),
                new XElement("openEMS",
                    fdtd.ToXElement(),
                    new XElement("ContinuousStructure",
                        new XAttribute("CoordSystem", 0),
                        simulationSpace.ToXElement(),
                        grid.ToXElement()
                    )
                )
            );

            if (dut is CSXCAD.Ara.Module)
            {
                dut.Parent = m_endo;
            }

            string openEmsInput = Path.Combine(mainParameters.OutputDirectory, "openEMS_input.xml");
            doc.Save(openEmsInput);

            string nf2ffInput = Path.Combine(mainParameters.OutputDirectory, "nf2ff_input.xml");
            var nf2ff = new Postprocess.NF2FF(m_f0);
            nf2ff.ToXDocument().Save(nf2ffInput);
        }
        public void GenerateSarSimulationInput(string outputDirectory)
        {
            Compound simulationSpace = new Compound("space");
            Compound solidSpace = new Compound("solid-space");
            simulationSpace.Add(solidSpace);
            solidSpace.Add(endo);

            var headPhantom = new CSXCAD.Ara.HeadPhantom();
            headPhantom.Transformations.Add(new TRotateX(Math.PI / 2));
            headPhantom.Transformations.Add(new TTranslate(32.0, 80.0, -headPhantom.Width / 2 - 7.0)); // TODO: Make endo width/height accessibles
            solidSpace.Add(headPhantom);

            double airBox = 40;
            double envResolution = Math.Round(lambdaMin / 20 / unit);
            double maxRatio = 1.5;

            RectilinearGrid grid = new BoundingGrid_6x3();

            Vector3D dutPosition = new Vector3D(
                antenna.AbsoluteTransformation.X,
                antenna.AbsoluteTransformation.Y,
                antenna.AbsoluteTransformation.Z);

            solidSpace.Transformations.Add(new TTranslate(-dutPosition));

            grid.Move(-dutPosition);
            grid.Add(new Vector3D(0, 0, 0));
            grid.ZLines.Add(-(antenna.Parent as CSXCAD.Ara.PCB).Thickness);
            grid.Sort();
            grid.SmoothMesh(dutResolution, maxRatio);

            grid.Add(headPhantom.BoundingBox.P1);
            grid.Add(headPhantom.BoundingBox.P2);
            grid.SmoothMesh(sarResolution, maxRatio);

            grid.AddAirbox(airBox);
            grid.SmoothMesh(envResolution, maxRatio);

            simulationSpace.Add(new SARBox("SAR", frequency,
                new Vector3D(headPhantom.XGridPoints.First(), headPhantom.YGridPoints.First(), headPhantom.ZGridPoints.First()),
                new Vector3D(headPhantom.XGridPoints.Last(), headPhantom.YGridPoints.Last(), headPhantom.ZGridPoints.Last())));
            simulationSpace.Add(new NF2FFBox("nf2ff",
                new Vector3D(grid.XLines.First(), grid.YLines.First(), grid.ZLines.First()),
                new Vector3D(grid.XLines.Last(), grid.YLines.Last(), grid.ZLines.Last()),
                lambdaMin / 15 / unit));

            grid.AddPML(8);

            Simulation fdtd = new Simulation();
            fdtd.Excitation = new GaussExcitation(frequency, bandwidth);

            // Export
            XDocument doc = new XDocument(
                new XDeclaration("1.0", "utf-8", "yes"),
                new XComment("CyPhy generated openEMS simulation file"),
                new XElement("openEMS",
                    fdtd.ToXElement(),
                    new XElement("ContinuousStructure",
                        new XAttribute("CoordSystem", 0),
                        simulationSpace.ToXElement(),
                        grid.ToXElement()
                    )
                )
            );

            System.IO.Directory.CreateDirectory(Path.Combine(outputDirectory));
            string openEmsInput = Path.Combine(outputDirectory, "openEMS_input.xml");
            doc.Save(openEmsInput);

            string nf2ffInput = Path.Combine(outputDirectory, "nf2ff_input.xml");
            var nf2ff = new Postprocess.NF2FF(frequency);
            nf2ff.ToXDocument().Save(nf2ffInput);

            File.WriteAllText(Path.Combine(outputDirectory, "run_sar.cmd"), AraRFAnalysis.Properties.Resources.run_sar);
        }
        public void GenerateFarFieldSimulationInput(string outputDirectory)
        {
            Compound simulationSpace = new Compound("space");
            Compound solidSpace = new Compound("solid-space");
            simulationSpace.Add(solidSpace);

            Compound dut;
            if (excludeEndo == true)
            {
                dut = endo.GetModule(slotIndex);
            }
            else
            {
                dut = endo;
            }
            solidSpace.Add(dut); // modifies dut parent (!)

            double airBox = 40;
            double maxRes = Math.Round(lambdaMin / 20 / unit);
            double maxRatio = 1.5;

            RectilinearGrid grid = new RectilinearGrid();
            grid.Add(dut.BoundingBox.P1);
            grid.Add(dut.BoundingBox.P2);

            Vector3D antennaPosition = new Vector3D(
                antenna.AbsoluteTransformation.X,
                antenna.AbsoluteTransformation.Y,
                antenna.AbsoluteTransformation.Z);

            solidSpace.Transformations.Add(new TTranslate(-antennaPosition));

            grid.Move(-antennaPosition);
            grid.Add(new Vector3D(0, 0, 0));
            grid.ZLines.Add(-(antenna.Parent as CSXCAD.Ara.PCB).Thickness);
            grid.Sort();

            grid.SmoothMesh(dutResolution, maxRatio);
            grid.AddAirbox(airBox);
            grid.SmoothMesh(maxRes, maxRatio);

            simulationSpace.Add(new NF2FFBox("nf2ff",
                new Vector3D(grid.XLines.First(), grid.YLines.First(), grid.ZLines.First()),
                new Vector3D(grid.XLines.Last(), grid.YLines.Last(), grid.ZLines.Last()),
                lambdaMin / 15 / unit));

            grid.AddPML(8);

            Simulation fdtd = new Simulation();
            fdtd.Excitation = new GaussExcitation(frequency, bandwidth);

            // Export
            XDocument doc = new XDocument(
                new XDeclaration("1.0", "utf-8", "yes"),
                new XComment("CyPhy generated openEMS simulation file"),
                new XElement("openEMS",
                    fdtd.ToXElement(),
                    new XElement("ContinuousStructure",
                        new XAttribute("CoordSystem", 0),
                        simulationSpace.ToXElement(),
                        grid.ToXElement()
                    )
                )
            );

            if (dut is CSXCAD.Ara.Module)
            {
                dut.Parent = endo;
            }

            System.IO.Directory.CreateDirectory(outputDirectory);
            string openEmsInput = Path.Combine(outputDirectory, "openEMS_input.xml");
            doc.Save(openEmsInput);

            string nf2ffInput = Path.Combine(outputDirectory, "nf2ff_input.xml");
            var nf2ff = new Postprocess.NF2FF(frequency);
            nf2ff.ToXDocument().Save(nf2ffInput);

            File.WriteAllText(Path.Combine(outputDirectory, "run_farfield.cmd"), AraRFAnalysis.Properties.Resources.run_farfield);
        }