String selectedTag = ""; if (java.util.Arrays.asList(model.component().tags()).contains("comp1") && java.util.Arrays.asList(model.sol().tags()).contains("nrel_sol")) { if (java.util.Arrays.asList( model.component("comp1").selection().tags() ).contains("nrel_air")) { selectedTag = model.tag(); } } if (selectedTag.length() == 0) { java.util.ArrayList candidates = new java.util.ArrayList(); for (String tag : com.comsol.model.util.ModelUtil.tags()) { com.comsol.model.Model candidate = com.comsol.model.util.ModelUtil.model(tag); if (!java.util.Arrays.asList( candidate.component().tags() ).contains("comp1")) { continue; } if (java.util.Arrays.asList(candidate.sol().tags()) .contains("nrel_sol") && java.util.Arrays.asList( candidate.component("comp1").selection().tags() ).contains("nrel_air")) { candidates.add(tag); } } if (candidates.size() != 1) { throw new IllegalStateException( "无法唯一定位 NREL 流场模型,候选:" + candidates ); } selectedTag = candidates.get(0); } model = com.comsol.model.util.ModelUtil.model(selectedTag); int[] airDomains = model.component("comp1").selection("nrel_air").entities(3); if (airDomains.length == 0) { throw new IllegalStateException("空气域选择为空。"); } int[] wallBoundaries = new int[0]; if (java.util.Arrays.asList( model.component("comp1").selection().tags() ).contains("nrel_blade_wall")) { wallBoundaries = model.component("comp1").selection("nrel_blade_wall").entities(2); } String dataTag = "nrel_cloud_solution"; if (!java.util.Arrays.asList( model.result().dataset().tags() ).contains(dataTag)) { model.result().dataset().create(dataTag, "Solution"); } else if (!"Solution".equals( model.result().dataset(dataTag).getType())) { throw new IllegalStateException("已有流场数据集类型不匹配。"); } model.result().dataset(dataTag).set("solution", "nrel_sol"); model.result().dataset(dataTag).set("comp", "comp1"); model.result().dataset(dataTag).selection().geom("geom1", 3); model.result().dataset(dataTag).selection().set(airDomains); // Q = 0.5*(旋转张量平方范数 - 应变率张量平方范数) // 直接使用速度空间导数,不依赖物理场专用 Q 变量名称。 String qExpr = "-0.5*(d(u,x)^2+d(v,y)^2+d(w,z)^2" + "+2*d(u,y)*d(v,x)" + "+2*d(u,z)*d(w,x)" + "+2*d(v,z)*d(w,y))"; String[] plotTags = new String[]{ "nrel_vortex_q1", "nrel_vortex_q5", "nrel_vortex_q20" }; String[] thresholds = new String[]{ "1[1/s^2]", "5[1/s^2]", "20[1/s^2]" }; for (int i = 0; i < plotTags.length; i++) { String tag = plotTags[i]; if (!java.util.Arrays.asList(model.result().tags()).contains(tag)) { model.result().create(tag, "PlotGroup3D"); } else if (!"PlotGroup3D".equals(model.result(tag).getType())) { throw new IllegalStateException("同名节点不是三维绘图组:" + tag); } model.result(tag).label("涡结构:Q=" + thresholds[i]); model.result(tag).set("data", dataTag); if (!java.util.Arrays.asList( model.result(tag).feature().tags() ).contains("iso1")) { model.result(tag).create("iso1", "Isosurface"); } else if (!"Isosurface".equals( model.result(tag).feature("iso1").getType())) { throw new IllegalStateException("iso1 类型不匹配:" + tag); } model.result(tag).feature("iso1").set("data", dataTag); model.result(tag).feature("iso1").set("expr", qExpr); model.result(tag).feature("iso1").set("unit", "1/s^2"); model.result(tag).feature("iso1").set("descr", "Q 判据涡结构"); model.result(tag).feature("iso1").set("levelmethod", "levels"); model.result(tag).feature("iso1") .set("levels", new String[]{thresholds[i]}); model.result(tag).feature("iso1").set("coloring", "uniform"); model.result(tag).feature("iso1").set("color", "cyan"); if (!java.util.Arrays.asList( model.result(tag).feature("iso1").feature().tags() ).contains("sel1")) { model.result(tag).feature("iso1").create("sel1", "Selection"); } model.result(tag).feature("iso1").feature("sel1") .selection().geom("geom1", 3); model.result(tag).feature("iso1").feature("sel1") .selection().set(airDomains); // 叠加叶轮壁面压力,帮助辨认涡结构与叶片的位置关系。 if (wallBoundaries.length > 0) { if (!java.util.Arrays.asList( model.result(tag).feature().tags() ).contains("blade1")) { model.result(tag).create("blade1", "Surface"); } else if (!"Surface".equals( model.result(tag).feature("blade1").getType())) { throw new IllegalStateException("blade1 类型不匹配:" + tag); } model.result(tag).feature("blade1").set("data", dataTag); model.result(tag).feature("blade1").set("expr", "p"); model.result(tag).feature("blade1").set("unit", "Pa"); model.result(tag).feature("blade1").set("descr", "叶轮壁面压力"); if (!java.util.Arrays.asList( model.result(tag).feature("blade1").feature().tags() ).contains("sel1")) { model.result(tag).feature("blade1").create("sel1", "Selection"); } model.result(tag).feature("blade1").feature("sel1") .selection().geom("geom1", 2); model.result(tag).feature("blade1").feature("sel1") .selection().set(wallBoundaries); } } // 先显示最低阈值,另外两张图按需点击绘制。 model.result("nrel_vortex_q1").run(); System.out.println("已添加 Q=1、5、20 [1/s²] 三个涡结构绘图组。"); System.out.println("青色表示 Q 等值面;叶轮表面颜色表示压力。"); System.out.println("阈值越高,一般只保留更强的局部涡结构。"); System.out.println("若只有叶轮而没有等值面,该阈值可能不在当前 Q 场范围内。"); System.out.println("当前图来自粗网格定常冻结转子解,不能代表瞬态尾涡演化。"); System.out.println("本轮未启动求解,未修改几何或网格。");