function export_comsol_normE_from_dat(varargin) %EXPORT_COMSOL_NORME_FROM_DAT 按 dat 中 Vertex 顺序从 COMSOL 插值 normE % % export_comsol_normE_from_dat % export_comsol_normE_from_dat('normExpr', 'ewfd.Ex*conj(ewfd.Ex)+...') % export_comsol_normE_from_dat('exExpr', 'ewfd.Ex', 'eyExpr', 'ewfd.Ey', 'ezExpr', 'ewfd.Ez') % % 若 normExpr 未指定或为空,将自动探测 Ex/Ey/Ez 并组合成 normE。 % 若模型没有预定义 normE 变量(emw.normE 报错即属此类),请用自动探测或手动指定分量。 opts = parseOpts(varargin); datPath = opts.datFile; if ~isfile(datPath) error('找不到网格文件: %s(请先 getMesh + export 生成 SBCmesh.dat)', datPath); end if ~isfile(opts.mphFile) error('找不到 COMSOL 模型: %s', opts.mphFile); end [V, nbr] = load_dat_vertices(datPath); fprintf('已从 %s 读取 %d 个顶点(dat 顺序)\n', datPath, nbr); model = mphload(opts.mphFile); coord = V.'; % mphinterp: 3×N probeCoord = mean(V, 1).'; if opts.autoDetect info = resolve_comsol_e_field(model, probeCoord); if isempty(opts.exExpr) opts.exExpr = info.exExpr; opts.eyExpr = info.eyExpr; opts.ezExpr = info.ezExpr; end if isempty(opts.normExpr) opts.normExpr = info.normExpr; end end if isempty(opts.normExpr) if isempty(opts.exExpr) error(['未指定 normExpr,且自动探测失败。\n', ... '请先运行 probe_comsol_fields,或手动传入 ex/ey/ez 表达式。']); end opts.normExpr = sprintf('sqrt(%s*conj(%s)+%s*conj(%s)+%s*conj(%s))', ... opts.exExpr, opts.exExpr, opts.eyExpr, opts.eyExpr, opts.ezExpr, opts.ezExpr); end fprintf('正在插值 normE 表达式:\n %s\n', opts.normExpr); normE = mphinterp(model, opts.normExpr, 'coord', coord); normE = real(normE(:)); if numel(normE) ~= nbr error('插值结果长度 %d 与顶点数 %d 不一致', numel(normE), nbr); end nanMask = isnan(normE) | isinf(normE); if any(nanMask) warning('export_comsol_normE:NaN', ... '%d 个顶点插值为 NaN/Inf(可能落在网格外或未求解)', nnz(nanMask)); end if opts.exportComponents fprintf('正在插值 Ex/Ey/Ez ...\n'); Ex = mphinterp(model, opts.exExpr, 'coord', coord); Ey = mphinterp(model, opts.eyExpr, 'coord', coord); Ez = mphinterp(model, opts.ezExpr, 'coord', coord); end if ~exist(opts.outDir, 'dir') mkdir(opts.outDir); end writeNormE(fullfile(opts.outDir, 'normE'), normE); if opts.exportComponents writeComplexField(fullfile(opts.outDir, 'Ex'), Ex); writeComplexField(fullfile(opts.outDir, 'Ey'), Ey); writeComplexField(fullfile(opts.outDir, 'Ez'), Ez); end if opts.exportTable T = [(1:nbr).', V, normE]; writematrix(T, fullfile(opts.outDir, 'vertex_normE.dat'), 'Delimiter', 'tab'); end metaFile = fullfile(opts.outDir, 'comsol_expr.txt'); fid = fopen(metaFile, 'w'); if fid > 0 fprintf(fid, 'normExpr=%s\n', opts.normExpr); fprintf(fid, 'exExpr=%s\n', opts.exExpr); fprintf(fid, 'eyExpr=%s\n', opts.eyExpr); fprintf(fid, 'ezExpr=%s\n', opts.ezExpr); fclose(fid); end fprintf('已写出 %s\n', fullfile(opts.outDir, 'normE')); fprintf(' max(normE) = %.12g\n', max(normE(~nanMask))); fprintf(' 行顺序与 %s 的 Vertex 第 1..%d 行一一对应\n', datPath, nbr); end function opts = parseOpts(args) p = inputParser; p.addParameter('mphFile', 'SBC.mph', @ischar); p.addParameter('datFile', 'SBCmesh.dat', @ischar); p.addParameter('normExpr', '', @ischar); p.addParameter('exExpr', '', @ischar); p.addParameter('eyExpr', '', @ischar); p.addParameter('ezExpr', '', @ischar); p.addParameter('outDir', 'OutFile_comsol', @ischar); p.addParameter('exportComponents', false, @islogical); p.addParameter('exportTable', true, @islogical); p.addParameter('autoDetect', true, @islogical); p.parse(args{:}); opts = p.Results; end function writeNormE(path, normE) fid = fopen(path, 'w'); if fid < 0 error('无法写入: %s', path); end c = onCleanup(@() fclose(fid)); fprintf(fid, '//\n'); fprintf(fid, '%.12g\n', normE); end function writeComplexField(path, field) fid = fopen(path, 'w'); if fid < 0 error('无法写入: %s', path); end c = onCleanup(@() fclose(fid)); fprintf(fid, '//\n'); fprintf(fid, '%.12g %.12g\n', [real(field(:)), imag(field(:))].'); end