/*
 * planoconvex_lens_orientation.java
 */

import com.comsol.model.*;
import com.comsol.model.util.*;

/** Model exported on May 15 2026, 09:25 by COMSOL 6.4.0.421. */
public class planoconvex_lens_orientation {

  public static Model run() {
    Model model = ModelUtil.create("Model");

//    From the File menu, choose New.
//    In the New window, click Model Wizard.
//    In the Model Wizard window, click 3D.
//    In the Select Physics tree, select Optics > Ray Optics > Geometrical Optics (gop).
//    Click Add.
//    Click Study.
//    In the Select Study tree, select Preset Studies for Selected Physics Interfaces > Ray Tracing.
//    Click Done.

    model.component().create("comp1", true);

    model.component("comp1").geom().create("geom1", 3);
    model.component("comp1").geom("geom1").geomRep("comsol");

    model.component("comp1").mesh().create("mesh1");
    model.component("comp1").mesh("mesh1").contribute("geom/detail", true);

    model.component("comp1").physics().create("gop", "GeometricalOptics", "geom1");

    model.study().create("std1");
    model.study("std1").create("rtrac", "RayTracing");

//    In the Model Builder window, under Component 1 (comp1), click Geometry 1.
//    In the Settings window for Geometry, locate the Units section.
//    From the Length unit list, select mm.

    model.component("comp1").geom("geom1").lengthUnit("mm");

//    In the Geometry toolbar, click Part Libraries.
//    In the Part Libraries window, select Ray Optics Module > 3D > Spherical Lenses > spherical_plano_convex_lens_3d in the tree.
//    Click Add to Geometry.
//    In the Select Part Variant dialog, select Specify effective focal length and center thickness in the Select part variant list.
//    Click OK.

    model.geom()
         .load(new String[]{"part1"}, "Ray_Optics_Module/3D/Spherical_Lenses/spherical_plano_convex_lens_3d.mph", new String[]{"part2"});
    model.component("comp1").geom("geom1").create("pi1", "PartInstance");
    model.component("comp1").geom("geom1").feature("pi1").set("selkeepnoncontr", false);
    model.component("comp1").geom("geom1").feature("pi1").set("part", "part1");

//    In the Model Builder window, right-click Component 1 (comp1) > Geometry 1 > Spherical Plano-Convex Lens 3D 1 (pi1) and choose Duplicate.

    model.component("comp1").geom("geom1").feature().duplicate("pi2", "pi1");

//    In the Settings window for Part Instance, locate the Input Parameters section.
//    In the table, enter the following settings:

    model.component("comp1").geom("geom1").feature("pi2").setEntry("inputexpr", "niz", -1);

//    Locate the Position and Orientation of Output section.
//    Find the Displacement subsection.
//    In the ywi text field, type 100[mm].

    model.component("comp1").geom("geom1").feature("pi2").set("displ", new String[]{"0", "100[mm]", "0"});

//    In the zwi text field, type 7.5[mm].

    model.component("comp1").geom("geom1").feature("pi2").set("displ", new String[]{"0", "100[mm]", "7.5[mm]"});

//    Click Build All Objects.

    model.component("comp1").geom("geom1").runPre("fin");

//    Click the Go to YZ View button in the Graphics toolbar.

    model.component("comp1").geom("geom1").run();

//    In the Materials toolbar, click Blank Material.

    model.component("comp1").material().create("mat1", "Common");

//    In the Settings window for Material, locate the Material Contents section.
//    In the table, enter the following settings:

    model.component("comp1").material("mat1").propertyGroup()
         .create("RefractiveIndex", "RefractiveIndex", "Refractive_index");
    model.component("comp1").material("mat1").propertyGroup("RefractiveIndex").set("n", new String[]{"1.5"});

//    In the Model Builder window, under Component 1 (comp1), click Geometrical Optics (gop).
//    In the Settings window for Geometrical Optics, locate the Ray Release and Propagation section.
//    In the Maximum number of secondary rays text field, type 0.

    model.component("comp1").physics("gop").prop("MaximumSecondary").setIndex("MaximumSecondary", 0, 0);

//    Locate the Results section.
//    From the Results list, select Plot spot diagram and geometric MTF.

    model.component("comp1").physics("gop").prop("Results").setIndex("Results", "PlotSpotDiagramAndGeometricMTF", 0);

//    In the Model Builder window, under Component 1 (comp1) > Geometrical Optics (gop), click Material Discontinuity 1.
//    In the Settings window for Material Discontinuity, locate the Rays to Release section.
//    From the Release reflected rays list, select Never.

    model.component("comp1").physics("gop").feature("matd1").set("ReleaseReflectedRays", "Never");

//    In the Physics toolbar, click Global and choose Release from Grid.

    model.component("comp1").physics("gop").create("relg1", "ReleaseGrid", -1);

//    In the Settings window for Release from Grid, locate the Initial Coordinates section.
//    From the Grid type list, select Hexapolar.

    model.component("comp1").physics("gop").feature("relg1").set("GridType", "Hexapolar");

//    Specify the \[\mathbf{q}_\textrm{c}\] vector as

    model.component("comp1").physics("gop").feature("relg1").set("qcc", new String[]{"0", "0", "-10[mm]"});
    model.component("comp1").physics("gop").feature("relg1").set("rcc", new int[]{0, 0, 0});

//    Specify the \[\mathbf{r}_\textrm{c}\] vector as

    model.component("comp1").physics("gop").feature("relg1").set("rcc", new int[]{0, 0, 1});

//    In the \[R_\textrm{c}\] text field, type 20[mm].

    model.component("comp1").physics("gop").feature("relg1").set("Rc", "20[mm]");

//    In the \[N_\textrm{c}\] text field, type 25.

    model.component("comp1").physics("gop").feature("relg1").setIndex("Ncr", 25, 0);

//    Locate the Ray Direction Vector section.
//    Specify the \[\mathbf{L}_0\] vector as

    model.component("comp1").physics("gop").feature("relg1").set("L0", new int[]{0, 0, 1});

//    Right-click Release from Grid 1 and choose Duplicate.

    model.component("comp1").physics("gop").feature().duplicate("relg2", "relg1");

//    In the Settings window for Release from Grid, locate the Initial Coordinates section.
//    Specify the \[\mathbf{q}_\textrm{c}\] vector as

    model.component("comp1").physics("gop").feature("relg2").set("qcc", new String[]{"0", "100[mm]", "-10[mm]"});

//    In the Model Builder window, under Component 1 (comp1), click Mesh 1.
//    In the Settings window for Mesh, locate the Physics-Controlled Mesh section.
//    From the Element size list, select Coarser.

    model.component("comp1").mesh("mesh1").autoMeshSize(7);

//    Click Build All.

    model.component("comp1").mesh("mesh1").run();

//    In the Model Builder window, under Study 1, click Step 1: Ray Tracing.
//    In the Settings window for Ray Tracing, locate the Study Settings section.
//    In the Output times text field, type range(0,0.01,0.6).

    model.study("std1").feature("rtrac").set("tlist", "range(0,0.01,0.6)");

//    In the Study toolbar, click Compute.

    model.study("std1").createAutoSequences("all");

    model.sol("sol1").runAll();

    model.result().dataset().create("ray1", "Ray");
    model.result().dataset("ray1").set("solution", "sol1");
    model.result().dataset("ray1").set("posdof", new String[]{"comp1.qx", "comp1.qy", "comp1.qz"});
    model.result().dataset("ray1").set("geom", "geom1");
    model.result().dataset("ray1").set("rgeom", "pgeom_gop");
    model.result().dataset("ray1").set("rgeomspec", "fromphysics");
    model.result().dataset("ray1").set("physicsinterface", "gop");
    model.result().create("pg1", "PlotGroup3D");
    model.result("pg1").set("data", "ray1");
    model.result("pg1").label("Ray Trajectories (gop)");
    model.result("pg1").create("rtrj1", "RayTrajectories");
    model.result("pg1").feature("rtrj1").set("linetype", "line");
    model.result("pg1").feature("rtrj1").create("col1", "Color");
    model.result("pg1").feature("rtrj1").feature("col1").set("expr", "t");
    model.result("pg1").feature("rtrj1").create("filt1", "RayTrajectoriesFilter");
    model.result().create("pg2", "PlotGroup2D");
    model.result("pg2").label("Spot Diagram");
    model.result("pg2").create("spot1", "SpotDiagram");
    model.result().dataset().create("ip1", "IntersectionPoint3D");
    model.result().dataset("ip1").set("data", "ray1");
    model.result("pg2").feature("spot1").set("data", "ip1");
    model.result("pg2").run();
    model.result("pg2").feature("spot1").runCommand("recomputeFocalPlaneDataset");
    model.result().create("pg3", "PlotGroup1D");
    model.result("pg3").label("Geometric MTF");
    model.result("pg3").set("data", "none");
    model.result("pg3").set("xlabelactive", true);
    model.result("pg3").set("xlabel", "Frequency (1/mm)");
    model.result("pg3").set("ylabelactive", true);
    model.result("pg3").set("ylabel", "MTF");
    model.result("pg3").set("titletype", "manual");
    model.result("pg3").set("title", "Geometric Modulation Transfer Function (MTF)");
    model.result().evaluationGroup().create("eg1", "EvaluationGroup");
    model.result().evaluationGroup("eg1").label("LSF Data (relg1)");
    model.result().evaluationGroup("eg1").set("data", "ip1");
    model.result().evaluationGroup("eg1").set("transpose", true);
    model.result().evaluationGroup("eg1").set("concatenation", "vertical");
    model.result().evaluationGroup("eg1").set("tablebuffersize", 100000);
    model.result().evaluationGroup("eg1").create("ray1", "Ray");
    model.result().evaluationGroup("eg1").feature("ray1").set("data", "ip1");
    model.result().evaluationGroup("eg1").feature("ray1").set("expr", "if(gop.prf==1, ip1y, NaN)");
    model.result().evaluationGroup("eg1").feature("ray1").set("unit", "mm");
    model.result().evaluationGroup("eg1").create("ray2", "Ray");
    model.result().evaluationGroup("eg1").feature("ray2").set("data", "ip1");
    model.result().evaluationGroup("eg1").feature("ray2").set("expr", "if(gop.prf==1, ip1x, NaN)");
    model.result().evaluationGroup("eg1").feature("ray2").set("unit", "mm");
    model.result().evaluationGroup("eg1").run();
    model.result().dataset().create("kde1", "KernelDensityEstimation");
    model.result().dataset("kde1").label("LSFx (eg1)");
    model.result().dataset("kde1").set("kerneltype", "parabolic");
    model.result().dataset("kde1").set("source", "evaluationgroup");
    model.result().dataset("kde1").set("evaluationgroup", "eg1");
    model.result().dataset("kde1").set("xaxisdata", "1");
    model.result().dataset("kde1").set("xvar", "eg1_x");
    model.result().dataset("kde1").set("outvar", "eg1_pdf_x");
    model.result().dataset().create("kde2", "KernelDensityEstimation");
    model.result().dataset("kde2").label("LSFy (eg1)");
    model.result().dataset("kde2").set("kerneltype", "parabolic");
    model.result().dataset("kde2").set("source", "evaluationgroup");
    model.result().dataset("kde2").set("evaluationgroup", "eg1");
    model.result().dataset("kde2").set("xaxisdata", "2");
    model.result().dataset("kde2").set("xvar", "eg1_x");
    model.result().dataset("kde2").set("outvar", "eg1_pdf_y");
    model.result().dataset().create("sfft1", "SpatialFFT");
    model.result().dataset("sfft1").label("MTFx (eg1)");
    model.result().dataset("sfft1").set("data", "kde1");
    model.result().dataset("sfft1").set("gridres", "manual");
    model.result().dataset("sfft1").set("sampresx", 32);
    model.result().dataset("sfft1").set("layout", "padding");
    model.result().dataset("sfft1").set("padx", 992);
    model.result().dataset("sfft1").set("maskdc", false);
    model.result().dataset("sfft1").set("normalizebydc", true);
    model.result().dataset("sfft1").set("fxvar", "eg1_fx");
    model.result().dataset().create("sfft2", "SpatialFFT");
    model.result().dataset("sfft2").label("MTFy (eg1)");
    model.result().dataset("sfft2").set("data", "kde2");
    model.result().dataset("sfft2").set("gridres", "manual");
    model.result().dataset("sfft2").set("sampresx", 32);
    model.result().dataset("sfft2").set("layout", "padding");
    model.result().dataset("sfft2").set("padx", 992);
    model.result().dataset("sfft2").set("maskdc", false);
    model.result().dataset("sfft2").set("normalizebydc", true);
    model.result().dataset("sfft2").set("fxvar", "eg1_fx");
    model.result("pg3").create("lngr1", "LineGraph");
    model.result("pg3").feature("lngr1").set("markerpos", "datapoints");
    model.result("pg3").feature("lngr1").set("linewidth", "preference");
    model.result("pg3").feature("lngr1").set("data", "sfft1");
    model.result("pg3").feature("lngr1").set("expr", "abs(fft(eg1_pdf_x))");
    model.result("pg3").feature("lngr1").set("xdata", "expr");
    model.result("pg3").feature("lngr1").set("xdataexpr", "eg1_fx");
    model.result("pg3").feature("lngr1").set("legendmethod", "manual");
    model.result("pg3").feature("lngr1").setIndex("legends", "MTFx (relg1)", 0);
    model.result("pg3").feature("lngr1").label("MTFx (relg1)");
    model.result("pg3").feature("lngr1").set("legend", true);
    model.result("pg3").create("lngr2", "LineGraph");
    model.result("pg3").feature("lngr2").set("markerpos", "datapoints");
    model.result("pg3").feature("lngr2").set("linewidth", "preference");
    model.result("pg3").feature("lngr2").set("data", "sfft2");
    model.result("pg3").feature("lngr2").set("expr", "abs(fft(eg1_pdf_y))");
    model.result("pg3").feature("lngr2").set("xdata", "expr");
    model.result("pg3").feature("lngr2").set("xdataexpr", "eg1_fx");
    model.result("pg3").feature("lngr2").set("legendmethod", "manual");
    model.result("pg3").feature("lngr2").setIndex("legends", "MTFy (relg1)", 0);
    model.result("pg3").feature("lngr2").label("MTFy (relg1)");
    model.result("pg3").feature("lngr2").set("legend", true);
    model.result().evaluationGroup().create("eg2", "EvaluationGroup");
    model.result().evaluationGroup("eg2").label("LSF Data (relg2)");
    model.result().evaluationGroup("eg2").set("data", "ip1");
    model.result().evaluationGroup("eg2").set("transpose", true);
    model.result().evaluationGroup("eg2").set("concatenation", "vertical");
    model.result().evaluationGroup("eg2").set("tablebuffersize", 100000);
    model.result().evaluationGroup("eg2").create("ray1", "Ray");
    model.result().evaluationGroup("eg2").feature("ray1").set("data", "ip1");
    model.result().evaluationGroup("eg2").feature("ray1").set("expr", "if(gop.prf==2, ip1y, NaN)");
    model.result().evaluationGroup("eg2").feature("ray1").set("unit", "mm");
    model.result().evaluationGroup("eg2").create("ray2", "Ray");
    model.result().evaluationGroup("eg2").feature("ray2").set("data", "ip1");
    model.result().evaluationGroup("eg2").feature("ray2").set("expr", "if(gop.prf==2, ip1x, NaN)");
    model.result().evaluationGroup("eg2").feature("ray2").set("unit", "mm");
    model.result().evaluationGroup("eg2").run();
    model.result().dataset().create("kde3", "KernelDensityEstimation");
    model.result().dataset("kde3").label("LSFx (eg2)");
    model.result().dataset("kde3").set("kerneltype", "parabolic");
    model.result().dataset("kde3").set("source", "evaluationgroup");
    model.result().dataset("kde3").set("evaluationgroup", "eg2");
    model.result().dataset("kde3").set("xaxisdata", "1");
    model.result().dataset("kde3").set("xvar", "eg2_x");
    model.result().dataset("kde3").set("outvar", "eg2_pdf_x");
    model.result().dataset().create("kde4", "KernelDensityEstimation");
    model.result().dataset("kde4").label("LSFy (eg2)");
    model.result().dataset("kde4").set("kerneltype", "parabolic");
    model.result().dataset("kde4").set("source", "evaluationgroup");
    model.result().dataset("kde4").set("evaluationgroup", "eg2");
    model.result().dataset("kde4").set("xaxisdata", "2");
    model.result().dataset("kde4").set("xvar", "eg2_x");
    model.result().dataset("kde4").set("outvar", "eg2_pdf_y");
    model.result().dataset().create("sfft3", "SpatialFFT");
    model.result().dataset("sfft3").label("MTFx (eg2)");
    model.result().dataset("sfft3").set("data", "kde3");
    model.result().dataset("sfft3").set("gridres", "manual");
    model.result().dataset("sfft3").set("sampresx", 32);
    model.result().dataset("sfft3").set("layout", "padding");
    model.result().dataset("sfft3").set("padx", 992);
    model.result().dataset("sfft3").set("maskdc", false);
    model.result().dataset("sfft3").set("normalizebydc", true);
    model.result().dataset("sfft3").set("fxvar", "eg2_fx");
    model.result().dataset().create("sfft4", "SpatialFFT");
    model.result().dataset("sfft4").label("MTFy (eg2)");
    model.result().dataset("sfft4").set("data", "kde4");
    model.result().dataset("sfft4").set("gridres", "manual");
    model.result().dataset("sfft4").set("sampresx", 32);
    model.result().dataset("sfft4").set("layout", "padding");
    model.result().dataset("sfft4").set("padx", 992);
    model.result().dataset("sfft4").set("maskdc", false);
    model.result().dataset("sfft4").set("normalizebydc", true);
    model.result().dataset("sfft4").set("fxvar", "eg2_fx");
    model.result("pg3").create("lngr3", "LineGraph");
    model.result("pg3").feature("lngr3").set("markerpos", "datapoints");
    model.result("pg3").feature("lngr3").set("linewidth", "preference");
    model.result("pg3").feature("lngr3").set("data", "sfft3");
    model.result("pg3").feature("lngr3").set("expr", "abs(fft(eg2_pdf_x))");
    model.result("pg3").feature("lngr3").set("xdata", "expr");
    model.result("pg3").feature("lngr3").set("xdataexpr", "eg2_fx");
    model.result("pg3").feature("lngr3").set("legendmethod", "manual");
    model.result("pg3").feature("lngr3").setIndex("legends", "MTFx (relg2)", 0);
    model.result("pg3").feature("lngr3").label("MTFx (relg2)");
    model.result("pg3").feature("lngr3").set("legend", true);
    model.result("pg3").create("lngr4", "LineGraph");
    model.result("pg3").feature("lngr4").set("markerpos", "datapoints");
    model.result("pg3").feature("lngr4").set("linewidth", "preference");
    model.result("pg3").feature("lngr4").set("data", "sfft4");
    model.result("pg3").feature("lngr4").set("expr", "abs(fft(eg2_pdf_y))");
    model.result("pg3").feature("lngr4").set("xdata", "expr");
    model.result("pg3").feature("lngr4").set("xdataexpr", "eg2_fx");
    model.result("pg3").feature("lngr4").set("legendmethod", "manual");
    model.result("pg3").feature("lngr4").setIndex("legends", "MTFy (relg2)", 0);
    model.result("pg3").feature("lngr4").label("MTFy (relg2)");
    model.result("pg3").feature("lngr4").set("legend", true);
    model.result("pg1").run();

//    In the Ray Trajectories (gop) toolbar, click Volume.

    model.result("pg1").create("vol1", "Volume");
    model.result("pg1").feature("vol1").set("evaluationsettings", "parent");

//    In the Ray Trajectories (gop) toolbar, click Material Appearance.

    model.result("pg1").feature("vol1").create("mtrl1", "MaterialAppearance");

//    Click the Show Grid button in the Graphics toolbar.

    model.component("comp1").view("view1").set("showgrid", false);

//    Click the Rotate Right 90° button in the Graphics toolbar.
//    Click the Zoom Extents button in the Graphics toolbar.
//    Click the Go to Default View button in the Graphics toolbar.
//    In the Model Builder window, expand the Results > Datasets node, then click Intersection Point 3D 1.
//    In the Settings window for Intersection Point 3D, locate the Surface section.
//    Find the Point subsection.
//    In the x text field, type 0.

    model.result().dataset("ip1").setIndex("genpnpoint", 0, 0);

//    In the y text field, type 0.

    model.result().dataset("ip1").setIndex("genpnpoint", 0, 1);

//    In the z text field, type 150[mm].

    model.result().dataset("ip1").set("genpnpoint", new String[]{"0", "0", "150[mm]"});
    model.result("pg2").run();

//    In the Model Builder window, under Results, click Spot Diagram.
//    In the Spot Diagram toolbar, click Plot.

    model.result("pg2").run();

//    Click the Zoom Extents button in the Graphics toolbar.
//    In the Model Builder window, click LSF Data (relg1).
//    In the LSF Data (relg1) toolbar, click Evaluate.

    model.result().evaluationGroup("eg1").run();

//    In the Model Builder window, click LSF Data (relg2).
//    In the LSF Data (relg2) toolbar, click Evaluate.

    model.result().evaluationGroup("eg2").run();
    model.result("pg3").run();

//    In the Model Builder window, click Geometric MTF.
//    In the Settings window for 1D Plot Group, locate the Axis section.
//    Select the Manual axis limits checkbox.

    model.result("pg3").set("axislimits", true);

//    In the x minimum text field, type 0.

    model.result("pg3").set("xmin", 0);

//    In the x maximum text field, type 10.

    model.result("pg3").set("xmax", 10);
    model.result("pg3").run();

//    In the Model Builder window, expand the Geometric MTF node, then click MTFy (relg1).
//    In the Settings window for Line Graph, click to expand the Coloring and Style section.
//    Find the Line style subsection.
//    From the Line list, select Dash-dot.

    model.result("pg3").feature("lngr2").set("linestyle", "dashdot");
    model.result("pg3").run();

//    In the Model Builder window, click MTFy (relg2).
//    In the Settings window for Line Graph, click to expand the Coloring and Style section.
//    Find the Line style subsection.
//    From the Line list, select Dash-dot.

    model.result("pg3").feature("lngr4").set("linestyle", "dashdot");

//    In the Geometric MTF toolbar, click Plot.

    model.result("pg3").run();

    model.title("Plano-Convex Lens Orientation");

    model
         .description("Light collimation or focusing is a basic task often needed when working with lasers in the lab where singlets are used due to their simplicity. If a plano-convex lens is used for the task, there is a correct lens orientation that minimizes aberrations. A useful rule-of-thumb is to minimize ray refraction at every surface which can be achieved by placing the lens with the curved side facing the collimated beam.");

    return model;
  }

  public static void main(String[] args) {
    run();
  }

}
