/*
 * electroosmotic_mixer.java
 */

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

/** Model exported on May 14 2026, 08:06 by COMSOL 6.4.0.420. */
public class electroosmotic_mixer {

  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 2D.
//    In the Select Physics tree, select Chemical Species Transport > Reacting Flow > Laminar Flow, Diluted Species.
//    Click Add.
//    In the Select Physics tree, select AC/DC > Electric Fields and Currents > Electric Currents (ec).
//    Click Add.
//    Click Study.
//    In the Select Study tree, select General Studies > Stationary.
//    Click Done.

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

    model.component("comp1").geom().create("geom1", 2);

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

    model.component("comp1").physics().create("spf", "LaminarFlow", "geom1");
    model.component("comp1").physics().create("tds", "DilutedSpecies", "geom1");
    model.component("comp1").physics().create("ec", "ConductiveMedia", "geom1");

    model.component("comp1").multiphysics().create("rfd1", "ReactingFlowDS", 2);
    model.component("comp1").multiphysics("rfd1").set("Fluid_physics", "spf");
    model.component("comp1").multiphysics("rfd1").set("Species_physics", "tds");

    model.study().create("std1");
    model.study("std1").create("stat", "Stationary");

//    In the Model Builder window, under Global Definitions, click Parameters 1.
//    In the Settings window for Parameters, locate the Parameters section.
//    In the table, enter the following settings:

    model.param().set("U0", "0.1[mm/s]");
    model.param().descr("U0", "Mean inflow velocity");
    model.param().set("sigma_w", "0.11845[S/m]");
    model.param().descr("sigma_w", "Conductivity of the ionic solution");
    model.param().set("eps_r", "80.2");
    model.param().descr("eps_r", "Relative permittivity of the fluid");
    model.param().set("zeta", "-0.1[V]");
    model.param().descr("zeta", "Zeta potential");
    model.param().set("V0", "0.1[V]");
    model.param().descr("V0", "Maximum value of the AC potential");
    model.param().set("omega", "2*pi[rad]*8[Hz]");
    model.param().descr("omega", "Angular frequency of the AC potential");
    model.param().set("t", "0[s]");
    model.param().descr("t", "Start time");
    model.param().set("D", "1e-11[m^2/s]");
    model.param().descr("D", "Diffusion coefficient of the solution");
    model.param().set("c0", "1[mol/m^3]");
    model.param().descr("c0", "Initial concentration");

//    You need the constant <c>t</c> (used in the scalar expressions below) when first solving the model using a stationary solver. In the time-dependent simulation, the internal time variable, <c>t</c>, overwrites this constant (the red color is just a warning signaling that t is an internal variable).
//    Now define a smoothed step function that you will later use to impose a step in the concentration in the middle of the channel entrance.
//    In the Home toolbar, click Functions and choose Global > Step.

    model.func().create("step1", "Step");

//    In the Settings window for Step, click to expand the Smoothing section.
//    In the Size of transition zone text field, type 0.1e-6.

    model.func("step1").set("smooth", "0.1e-6");

//    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 µm.

    model.component("comp1").geom("geom1").lengthUnit("\u00b5m");

//    In the Geometry toolbar, click Rectangle.

    model.component("comp1").geom("geom1").create("r1", "Rectangle");

//    In the Settings window for Rectangle, locate the Position section.
//    From the Base list, select Center.

    model.component("comp1").geom("geom1").feature("r1").set("base", "center");

//    Locate the Size and Shape section.
//    In the Width text field, type 80.

    model.component("comp1").geom("geom1").feature("r1").set("size", new double[]{80, 1});

//    In the Height text field, type 10.

    model.component("comp1").geom("geom1").feature("r1").set("size", new double[]{80, 10});

//    In the Geometry toolbar, click Circle.

    model.component("comp1").geom("geom1").run("r1");
    model.component("comp1").geom("geom1").create("c1", "Circle");

//    In the Settings window for Circle, locate the Size and Shape section.
//    In the Radius text field, type 15.

    model.component("comp1").geom("geom1").feature("c1").set("r", 15);

//    To add vertices for the electrode endpoints on the outer boundary, use the Partition Edges.
//    In the Geometry toolbar, click Booleans and Partitions and choose Partition Edges.

    model.component("comp1").geom("geom1").run("c1");
    model.component("comp1").geom("geom1").create("pare1", "PartitionEdges");

//    On the object c1, select Boundaries 1, 2, 3, 4.

    model.component("comp1").geom("geom1").feature("pare1").selection("edge").set("c1", 1, 2, 3, 4);

//    In the Settings window for Partition Edges, locate the Positions section.
//    In the table, enter the following settings:

    model.component("comp1").geom("geom1").feature("pare1").setIndex("param", 0.47, 0);
    model.component("comp1").geom("geom1").feature("pare1").setIndex("param", 0.53, 1);

//    In the Geometry toolbar, click Circle.

    model.component("comp1").geom("geom1").run("pare1");
    model.component("comp1").geom("geom1").create("c2", "Circle");

//    In the Settings window for Circle, locate the Size and Shape section.
//    In the Radius text field, type 5.

    model.component("comp1").geom("geom1").feature("c2").set("r", 5);

//    In the Geometry toolbar, click Booleans and Partitions and choose Compose.

    model.component("comp1").geom("geom1").run("c2");
    model.component("comp1").geom("geom1").create("co1", "Compose");

//    Click in the Graphics window and then press Ctrl+A to select all objects.

    model.component("comp1").geom("geom1").feature("co1").selection("input").set("c2", "pare1", "r1");

//    In the Settings window for Compose, locate the Compose section.
//    In the Set formula text field, type (r1+pare1)-c2.

    model.component("comp1").geom("geom1").feature("co1").set("formula", "(r1+pare1)-c2");

//    Clear the Keep interior boundaries checkbox.

    model.component("comp1").geom("geom1").feature("co1").set("intbnd", false);

//    In the Model Builder window, click Form Union (fin).
//    The model geometry is now complete.

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

//    In the Model Builder window, right-click Component 1 (comp1) > Materials and choose 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("def").set("density", new String[]{"1e3[kg/m^3]"});
    model.component("comp1").material("mat1").propertyGroup("def")
         .set("dynamicviscosity", new String[]{"1e-3[Pa*s]"});
    model.component("comp1").material("mat1").propertyGroup("def")
         .set("electricconductivity", new String[]{"sigma_w"});
    model.component("comp1").material("mat1").propertyGroup("def").set("relpermittivity", new String[]{"eps_r"});

//    In the Model Builder window, under Component 1 (comp1), click Laminar Flow (spf).
//    In the Settings window for Laminar Flow, click to expand the Discretization section.
//    From the Discretization of fluids list, select P2+P1.

    model.component("comp1").physics("spf").prop("ShapeProperty").set("order_fluid", 2);

//    Using higher-order elements can improve the accuracy of the solution significantly for low Reynolds number flows such as those in this model.
//    In the Physics toolbar, click Boundaries and choose Inlet.

    model.component("comp1").physics("spf").create("inl1", "InletBoundary", 1);

//    Select Boundary 1.

    model.component("comp1").physics("spf").feature("inl1").selection().set(1);

//    In the Settings window for Inlet, locate the Boundary Condition section.
//    From the list, select Fully developed flow.

    model.component("comp1").physics("spf").feature("inl1").set("BoundaryCondition", "FullyDevelopedFlow");

//    Locate the Fully Developed Flow section.
//    In the \[U_{\textrm{av}}\] text field, type U0.

    model.component("comp1").physics("spf").feature("inl1").set("Uavfdf", "U0");

//    In the Physics toolbar, click Boundaries and choose Outlet.

    model.component("comp1").physics("spf").create("out1", "OutletBoundary", 1);

//    Select Boundary 6.

    model.component("comp1").physics("spf").feature("out1").selection().set(6);

//    In the Model Builder window, click Wall 1.
//    In the Settings window for Wall, locate the Boundary Condition section.
//    From the Wall condition list, select Electroosmotic velocity.

    model.component("comp1").physics("spf").feature("wallbc1").set("BoundaryCondition", "ElectroosmoticVelocity");

//    Specify the \[\mathbf{E}\] vector as

    model.component("comp1").physics("spf").feature("wallbc1")
         .set("E", new String[]{"ec.Ex*sin(omega*t)", "ec.Ey*sin(omega*t)", "0"});

//    From the Electroosmotic mobility list, select Built-in expression.

    model.component("comp1").physics("spf").feature("wallbc1").set("ElectroosmoticOption", "BuiltinExpression");

//    In the \[\zeta\] text field, type zeta.

    model.component("comp1").physics("spf").feature("wallbc1").set("zeta", "zeta");

//    In the \[\epsilon_{\textrm{r}}\] text field, type eps_r.

    model.component("comp1").physics("spf").feature("wallbc1").set("epsilonr", "eps_r");

//    Raise the element order to match that of the <l>Laminar Flow</l> interface.
//    In the Model Builder window, under Component 1 (comp1), click Transport of Diluted Species (tds).
//    In the Settings window for Transport of Diluted Species, click to expand the Discretization section.
//    From the Concentration list, select Quadratic.

    model.component("comp1").physics("tds").prop("ShapeProperty").set("order_concentration", 2);

//    In the Model Builder window, under Component 1 (comp1) > Transport of Diluted Species (tds), click Fluid 1.
//    In the Settings window for Fluid, locate the Diffusion section.
//    In the \[D_{\textrm{c}}\] text field, type D.

    model.component("comp1").physics("tds").feature("cdm1")
         .set("D_c", new String[]{"D", "0", "0", "0", "D", "0", "0", "0", "D"});

//    Note that the velocity field for the species convection is controlled by the <l>Reacting Flow, Diluted Species</l> multiphysics coupling.
//    In the Physics toolbar, click Boundaries and choose Concentration.

    model.component("comp1").physics("tds").create("conc1", "Concentration", 1);

//    Select Boundary 1.

    model.component("comp1").physics("tds").feature("conc1").selection().set(1);

//    In the Settings window for Concentration, locate the Concentration section.
//    Select the Species c checkbox.

    model.component("comp1").physics("tds").feature("conc1").setIndex("species", true, 0);

//    In the \[c_{\textrm{0,{c}}}\] text field, type c0*step1(y[1/m]).

    model.component("comp1").physics("tds").feature("conc1").setIndex("c0", "c0*step1(y[1/m])", 0);

//    The concentration condition on boundaries 1 and 3 gives a sharp but smooth concentration gradient in the middle of the channel entrance.
//    In the Physics toolbar, click Boundaries and choose Outflow.

    model.component("comp1").physics("tds").create("out1", "Outflow", 1);

//    Select Boundary 6.

    model.component("comp1").physics("tds").feature("out1").selection().set(6);

//    In the Model Builder window, under Component 1 (comp1), click Electric Currents (ec).
//    In the Physics toolbar, click Boundaries and choose Electric Potential.

    model.component("comp1").physics("ec").create("pot1", "ElectricPotential", 1);

//    Select Boundaries 9, 20.

    model.component("comp1").physics("ec").feature("pot1").selection().set(9, 20);

//    In the Settings window for Electric Potential, locate the Electric Potential section.
//    In the \[V_\textrm{0}\] text field, type -V0.

    model.component("comp1").physics("ec").feature("pot1").set("V0", "-V0");

//    In the Physics toolbar, click Boundaries and choose Electric Potential.

    model.component("comp1").physics("ec").create("pot2", "ElectricPotential", 1);

//    Select Boundaries 10, 19.

    model.component("comp1").physics("ec").feature("pot2").selection().set(10, 19);

//    In the Settings window for Electric Potential, locate the Electric Potential section.
//    In the \[V_\textrm{0}\] text field, type V0.

    model.component("comp1").physics("ec").feature("pot2").set("V0", "V0");

//    In the Mesh toolbar, click Free Triangular.

    model.component("comp1").mesh("mesh1").create("ftri1", "FreeTri");

//    In the Model Builder window, click Size.
//    In the Settings window for Size, locate the Element Size section.
//    From the Predefined list, select Extra fine.

    model.component("comp1").mesh("mesh1").feature("size").set("hauto", 2);

//    In the Model Builder window, right-click Free Triangular 1 and choose Size.

    model.component("comp1").mesh("mesh1").feature("ftri1").create("size1", "Size");

//    In the Settings window for Size, locate the Geometric Entity Selection section.
//    From the Geometric entity level list, select Boundary.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").selection().geom("geom1", 1);

//    Select Boundaries 9, 10, 19, 20.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").selection().set(9, 10, 19, 20);

//    Locate the Element Size section.
//    Click the Custom button.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").set("custom", true);

//    Locate the Element Size Parameters section.
//    Select the Maximum element size checkbox.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").set("hmaxactive", true);

//    In the associated text field, type 0.2.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").set("hmax", 0.2);

//    Select the Maximum element growth rate checkbox.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").set("hgradactive", true);

//    In the associated text field, type 1.1.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").set("hgrad", 1.1);

//    Click Build All.

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

//    Set up the study to start by computing the stationary solution for velocity, pressure, concentration, and electric potential. Then, add a transient simulation stage that solves only for the variables of the <l>Laminar Flow</l> and <l>Transport of Diluted Species</l> interfaces. Begin by adding a study step for the transient part.
//    In the Study toolbar, click Time Dependent.

    model.study("std1").create("time", "Transient");

//    In the Settings window for Time Dependent, locate the Study Settings section.
//    In the Output times text field, type range(0,0.125/60,0.5).

    model.study("std1").feature("time").set("tlist", "range(0,0.125/60,0.5)");
    model.study("std1").feature("time").setSolveFor("/physics/ec", false);

//    Locate the Physics and Variables Selection section.
//    In the Solve for column of the table, under Component 1 (comp1), clear the checkbox for Electric Currents (ec).
//    In the Model Builder window, click Study 1.
//    In the Settings window for Study, locate the Study Settings section.
//    Clear the Generate default plots checkbox.

    model.study("std1").setGenPlots(false);

//    This is convenient if you want to create specialized plots while keeping the number of plot groups down.
//    In the Study toolbar, click Show Default Solver.

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

//    In the Model Builder window, expand the Solution 1 (sol1) node, then click Time-Dependent Solver 1.
//    In the Settings window for Time-Dependent Solver, click to expand the Absolute Tolerance section.
//    From the Tolerance method list, select Manual.

    model.sol("sol1").feature("t1").set("atolglobalvaluemethod", "manual");

//    In the Absolute tolerance text field, type 5.0E-5.

    model.sol("sol1").feature("t1").set("atolglobal", 5.0E-5);

//    In the Study toolbar, click Compute.

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

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

//    In the Results toolbar, click 2D Plot Group.

    model.result().create("pg1", "PlotGroup2D");
    model.result("pg1").run();

//    In the Settings window for 2D Plot Group, type Velocity, streamlines in the Label text field.

    model.result("pg1").label("Velocity, streamlines");

//    Locate the Data section.
//    From the Time (s) list, select 0.0375.

    model.result("pg1").setIndex("looplevel", 19, 0);

//    Right-click Velocity, streamlines and choose Streamline.

    model.result("pg1").create("str1", "Streamline");
    model.result("pg1").feature("str1").set("evaluationsettings", "parent");

//    In the Settings window for Streamline, click Replace Expression in the upper-right corner of the Expression section.
//    From the menu, choose Component 1 (comp1) > Laminar Flow > Velocity and pressure > u,v - Velocity field.

    model.result("pg1").feature("str1").set("expr", new String[]{"u", "v"});
    model.result("pg1").feature("str1").set("descr", "Velocity field");

//    Locate the Streamline Positioning section.
//    From the Positioning list, select Uniform density.

    model.result("pg1").feature("str1").set("posmethod", "uniform");

//    In the Density level text field, type 9.4.

    model.result("pg1").feature("str1").set("udensity", 9.4);

//    In the Velocity, streamlines toolbar, click Plot.

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

//    Click the Zoom Extents button in the Graphics toolbar.
//    Click the Zoom In button in the Graphics toolbar.
//    In the Results toolbar, click 2D Plot Group.

    model.result().create("pg2", "PlotGroup2D");
    model.result("pg2").run();

//    In the Settings window for 2D Plot Group, type Electric potential in the Label text field.

    model.result("pg2").label("Electric potential");

//    Locate the Data section.
//    From the Time (s) list, select 0.0375.

    model.result("pg2").setIndex("looplevel", 19, 0);

//    Right-click Electric potential and choose Contour.

    model.result("pg2").create("con1", "Contour");
    model.result("pg2").feature("con1").set("evaluationsettings", "parent");

//    In the Settings window for Contour, click Replace Expression in the upper-right corner of the Expression section.
//    From the menu, choose Component 1 (comp1) > Electric Currents > Electric > V - Electric potential - V.

    model.result("pg2").feature("con1").set("expr", "V");
    model.result("pg2").feature("con1").set("descr", "Electric potential");

//    In the Electric potential toolbar, click Plot.

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

//    Click the Zoom Extents button in the Graphics toolbar.
//    In the Results toolbar, click 2D Plot Group.

    model.result().create("pg3", "PlotGroup2D");
    model.result("pg3").run();

//    In the Settings window for 2D Plot Group, type Concentration in the Label text field.

    model.result("pg3").label("Concentration");

//    Right-click Concentration and choose Surface.

    model.result("pg3").create("surf1", "Surface");
    model.result("pg3").feature("surf1").set("evaluationsettings", "parent");

//    In the Settings window for Surface, click Replace Expression in the upper-right corner of the Expression section.
//    From the menu, choose Component 1 (comp1) > Transport of Diluted Species > Species c > c - Molar concentration, c - mol/m³.

    model.result("pg3").feature("surf1").set("expr", "c");
    model.result("pg3").feature("surf1").set("descr", "Molar concentration, c");
    model.result("pg3").run();

//    In the Model Builder window, right-click Concentration and choose Streamline.

    model.result("pg3").create("str1", "Streamline");
    model.result("pg3").feature("str1").set("evaluationsettings", "parent");

//    In the Settings window for Streamline, click Replace Expression in the upper-right corner of the Expression section.
//    From the menu, choose Component 1 (comp1) > Laminar Flow > Velocity and pressure > u,v - Velocity field.

    model.result("pg3").feature("str1").set("expr", new String[]{"u", "v"});
    model.result("pg3").feature("str1").set("descr", "Velocity field");

//    Locate the Streamline Positioning section.
//    From the Positioning list, select Uniform density.

    model.result("pg3").feature("str1").set("posmethod", "uniform");

//    In the Density level text field, type 9.4.

    model.result("pg3").feature("str1").set("udensity", 9.4);
    model.result("pg3").run();

//    In the Model Builder window, click Concentration.
//    In the Settings window for 2D Plot Group, locate the Data section.
//    From the Time (s) list, select 0.

    model.result("pg3").setIndex("looplevel", 1, 0);

//    In the Concentration toolbar, click Plot.

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

//    From the Time (s) list, select 0.46875.

    model.result("pg3").setIndex("looplevel", 226, 0);

//    In the Concentration toolbar, click Plot.

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

    model.title("Electroosmotic Micromixer");

    model
         .description("This example shows a micromixer that takes advantage of electroosmosis to mix fluids. A time-dependent electric field is applied, and the resulting electroosmosis perturbs the flow. Animations of the particle traces show an extensive folding and stretching of material lines.");

    return model;
  }

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

}
