513 lines
8.4 KiB
Matlab
513 lines
8.4 KiB
Matlab
function export_phy_to_json(phy, jsonFile, cfg)
|
||
|
||
%EXPORT_PHY_TO_JSON 由 phy + case_config 生成 OpticsFEM 散射 JSON(通用)。
|
||
|
||
% BoundaryFlag(i) = 网格面域 DomainOfTri 编号 i 的边界类型(0 PMC, 2 SBC, 4 PBC)。
|
||
|
||
|
||
|
||
if nargin < 1 || isempty(phy)
|
||
|
||
if ~exist('case_config', 'file')
|
||
|
||
error('未传入 phy,且当前目录无 case_config.m');
|
||
|
||
end
|
||
|
||
[phy, cfg] = case_config();
|
||
|
||
if nargin < 2 || isempty(jsonFile)
|
||
|
||
jsonFile = fullfile(pwd, cfg.jsonFile);
|
||
|
||
end
|
||
|
||
elseif nargin < 3 || isempty(cfg)
|
||
|
||
if exist('case_config', 'file')
|
||
|
||
[~, cfg] = case_config();
|
||
|
||
else
|
||
|
||
cfg = struct();
|
||
|
||
end
|
||
|
||
cfg = fill_cfg_defaults(cfg, phy);
|
||
|
||
if nargin < 2 || isempty(jsonFile)
|
||
|
||
if isfield(cfg, 'jsonFile')
|
||
|
||
jsonFile = fullfile(pwd, cfg.jsonFile);
|
||
|
||
else
|
||
|
||
jsonFile = fullfile(pwd, 'sbc3d.json');
|
||
|
||
end
|
||
|
||
end
|
||
|
||
else
|
||
|
||
cfg = fill_cfg_defaults(cfg, phy);
|
||
|
||
end
|
||
|
||
|
||
|
||
outFaces = phy.out(:)';
|
||
|
||
incFaces = phy.inc(:)';
|
||
|
||
sbcIndex = unique([outFaces, incFaces], 'stable');
|
||
|
||
nSbc = numel(sbcIndex);
|
||
|
||
sbcType = zeros(1, nSbc);
|
||
|
||
for k = 1:nSbc
|
||
|
||
if ismember(sbcIndex(k), incFaces)
|
||
|
||
sbcType(k) = 1;
|
||
|
||
else
|
||
|
||
sbcType(k) = 0;
|
||
|
||
end
|
||
|
||
end
|
||
|
||
|
||
|
||
[nbrBoundary, boundaryFlag] = infer_boundary_flag(phy, cfg);
|
||
|
||
|
||
|
||
nDom = numel(phy.eps);
|
||
|
||
doc = struct();
|
||
|
||
doc.FemType = cfg.FemType;
|
||
|
||
doc.EletricType = cfg.EletricType;
|
||
|
||
doc.lambda = phy.lda0;
|
||
|
||
doc.NbrBoundary = nbrBoundary;
|
||
|
||
doc.BoundaryFlag = boundaryFlag;
|
||
|
||
|
||
|
||
if isfield(phy, 'src') && isfield(phy, 'dst') && ~isempty(phy.src)
|
||
|
||
if isfield(cfg, 'pbcPhi')
|
||
|
||
pbcPhi = cfg.pbcPhi;
|
||
|
||
else
|
||
|
||
pbcPhi = exp(1i * 2 * pi / 6);
|
||
|
||
end
|
||
|
||
if isfield(cfg, 'pbcAngle')
|
||
|
||
pbcAngle = cfg.pbcAngle;
|
||
|
||
else
|
||
|
||
pbcAngle = pi / 3;
|
||
|
||
end
|
||
|
||
doc.pbc = struct( ...
|
||
|
||
'srcIndex', phy.src(:)', ...
|
||
|
||
'dstIndex', phy.dst(:)', ...
|
||
|
||
'phiR', real(pbcPhi(:)'), ...
|
||
|
||
'phiI', imag(pbcPhi(:)'), ...
|
||
|
||
'pbcAngle', pbcAngle);
|
||
|
||
end
|
||
|
||
|
||
|
||
doc.sbc = struct( ...
|
||
|
||
'Index', sbcIndex, ...
|
||
|
||
'SBCType', sbcType, ...
|
||
|
||
'E0x', {repmat({num2str(phy.Einc(1))}, 1, nSbc)}, ...
|
||
|
||
'E0y', {repmat({num2str(phy.Einc(2))}, 1, nSbc)}, ...
|
||
|
||
'E0z', {repmat({num2str(phy.Einc(3))}, 1, nSbc)}, ...
|
||
|
||
'kx', zeros(1, nSbc), ...
|
||
|
||
'ky', zeros(1, nSbc), ...
|
||
|
||
'kz', zeros(1, nSbc));
|
||
|
||
doc.NbrDomain = nDom;
|
||
|
||
doc.domainType = repmat(2, 1, nDom);
|
||
|
||
doc.domainIndex = 0:(nDom - 1);
|
||
|
||
doc.matType = zeros(1, nDom);
|
||
|
||
doc.epsilonrR = phy.eps(:)';
|
||
|
||
doc.epsilonrI = zeros(1, nDom);
|
||
|
||
doc.murR = phy.mur(:)';
|
||
|
||
doc.murI = zeros(1, nDom);
|
||
|
||
doc.chiheR = zeros(1, nDom);
|
||
|
||
doc.chiehR = zeros(1, nDom);
|
||
|
||
doc.chiheI = zeros(1, nDom);
|
||
|
||
doc.chiehI = zeros(1, nDom);
|
||
|
||
doc.sigma = zeros(1, nDom);
|
||
|
||
doc.n = ones(1, nDom);
|
||
|
||
doc.k = zeros(1, nDom);
|
||
|
||
doc.MeshFile = cfg.MeshFile;
|
||
|
||
doc.OutFile = cfg.OutFile;
|
||
|
||
|
||
|
||
txt = pretty_json(doc);
|
||
|
||
fid = fopen(jsonFile, 'w');
|
||
|
||
if fid < 0
|
||
|
||
error('无法写入: %s', jsonFile);
|
||
|
||
end
|
||
|
||
cleanup = onCleanup(@() fclose(fid));
|
||
|
||
fprintf(fid, '%s', txt);
|
||
|
||
fprintf('已写出 %s (%d 字节, lambda=%.4g, NbrBoundary=%d)\n', ...
|
||
|
||
jsonFile, length(txt), phy.lda0, doc.NbrBoundary);
|
||
|
||
end
|
||
|
||
|
||
|
||
function cfg = fill_cfg_defaults(cfg, phy)
|
||
|
||
if nargin < 2, phy = struct(); end
|
||
|
||
if ~isfield(cfg, 'FemType'), cfg.FemType = 4; end
|
||
|
||
if ~isfield(cfg, 'EletricType'), cfg.EletricType = 2; end
|
||
|
||
if ~isfield(cfg, 'MeshFile'), cfg.MeshFile = 'SBCmesh.dat'; end
|
||
|
||
if ~isfield(cfg, 'OutFile'), cfg.OutFile = './OutFile'; end
|
||
|
||
if ~isfield(cfg, 'NbrBoundary') || ~isfield(cfg, 'BoundaryFlag')
|
||
|
||
[cfg.NbrBoundary, cfg.BoundaryFlag] = infer_boundary_flag(phy, cfg);
|
||
|
||
end
|
||
|
||
end
|
||
|
||
|
||
|
||
function [nbrBoundary, boundaryFlag] = infer_boundary_flag(phy, cfg)
|
||
|
||
% Prefer explicit cfg; else build from phy face domains (PBC case 1..9).
|
||
|
||
if isfield(cfg, 'NbrBoundary') && isfield(cfg, 'BoundaryFlag') ...
|
||
|
||
&& numel(cfg.BoundaryFlag) == cfg.NbrBoundary
|
||
|
||
nbrBoundary = cfg.NbrBoundary;
|
||
|
||
boundaryFlag = cfg.BoundaryFlag;
|
||
|
||
return;
|
||
|
||
end
|
||
|
||
|
||
|
||
if isfield(phy, 'src') && isfield(phy, 'dst') && ~isempty(phy.src)
|
||
|
||
allDom = [phy.src(:); phy.dst(:); phy.out(:); phy.inc(:)];
|
||
|
||
nbrBoundary = max(allDom);
|
||
|
||
boundaryFlag = zeros(1, nbrBoundary);
|
||
|
||
for d = 1:nbrBoundary
|
||
|
||
if ismember(d, [phy.src(:); phy.dst(:)])
|
||
|
||
boundaryFlag(d) = 4;
|
||
|
||
elseif ismember(d, [phy.out(:); phy.inc(:)])
|
||
|
||
boundaryFlag(d) = 2;
|
||
|
||
else
|
||
|
||
boundaryFlag(d) = 0;
|
||
|
||
end
|
||
|
||
end
|
||
|
||
return;
|
||
|
||
end
|
||
|
||
|
||
|
||
% Legacy SBC full model (14 COMSOL boundaries)
|
||
|
||
nbrBoundary = 14;
|
||
|
||
boundaryFlag = [0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2];
|
||
|
||
end
|
||
|
||
|
||
|
||
function txt = pretty_json(doc)
|
||
|
||
lines = cell(1, 50);
|
||
|
||
n = 0;
|
||
|
||
n = n + 1; lines{n} = '{';
|
||
|
||
n = n + 1; lines{n} = sprintf(' "FemType": %d,', doc.FemType);
|
||
|
||
n = n + 1; lines{n} = sprintf(' "EletricType": %d,', doc.EletricType);
|
||
|
||
n = n + 1; lines{n} = sprintf(' "lambda": %s,', json_num(doc.lambda));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "NbrBoundary": %d,', doc.NbrBoundary);
|
||
|
||
n = n + 1; lines{n} = sprintf(' "BoundaryFlag": %s,', json_int_array(doc.BoundaryFlag));
|
||
|
||
|
||
|
||
if isfield(doc, 'pbc')
|
||
|
||
n = n + 1; lines{n} = ' "pbc": {';
|
||
|
||
n = n + 1; lines{n} = sprintf(' "srcIndex": %s,', json_int_array(doc.pbc.srcIndex));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "dstIndex": %s,', json_int_array(doc.pbc.dstIndex));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "phiR": %s,', json_float_array(doc.pbc.phiR));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "phiI": %s,', json_float_array(doc.pbc.phiI));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "pbcAngle": %s', json_num(doc.pbc.pbcAngle));
|
||
|
||
n = n + 1; lines{n} = ' },';
|
||
|
||
end
|
||
|
||
|
||
|
||
n = n + 1; lines{n} = ' "sbc": {';
|
||
|
||
n = n + 1; lines{n} = sprintf(' "Index": %s,', json_int_array(doc.sbc.Index));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "SBCType": %s,', json_int_array(doc.sbc.SBCType));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "E0x": %s,', json_str_array(doc.sbc.E0x));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "E0y": %s,', json_str_array(doc.sbc.E0y));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "E0z": %s,', json_str_array(doc.sbc.E0z));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "kx": %s,', json_int_array(doc.sbc.kx));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "ky": %s,', json_int_array(doc.sbc.ky));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "kz": %s', json_int_array(doc.sbc.kz));
|
||
|
||
n = n + 1; lines{n} = ' },';
|
||
|
||
n = n + 1; lines{n} = sprintf(' "NbrDomain": %d,', doc.NbrDomain);
|
||
|
||
n = n + 1; lines{n} = sprintf(' "domainType": %s,', json_int_array(doc.domainType));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "domainIndex": %s,', json_int_array(doc.domainIndex));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "matType": %s,', json_int_array(doc.matType));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "epsilonrR": %s,', json_float_array(doc.epsilonrR));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "epsilonrI": %s,', json_float_array(doc.epsilonrI));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "murR": %s,', json_float_array(doc.murR));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "murI": %s,', json_float_array(doc.murI));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "chiheR": %s,', json_float_array(doc.chiheR));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "chiehR": %s,', json_float_array(doc.chiehR));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "chiheI": %s,', json_float_array(doc.chiheI));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "chiehI": %s,', json_float_array(doc.chiehI));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "sigma": %s,', json_float_array(doc.sigma));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "n": %s,', json_float_array(doc.n));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "k": %s,', json_float_array(doc.k));
|
||
|
||
n = n + 1; lines{n} = sprintf(' "MeshFile": "%s",', doc.MeshFile);
|
||
|
||
n = n + 1; lines{n} = sprintf(' "OutFile": "%s"', doc.OutFile);
|
||
|
||
n = n + 1; lines{n} = '}';
|
||
|
||
lines = lines(1:n);
|
||
|
||
txt = join_lines(lines);
|
||
|
||
end
|
||
|
||
|
||
|
||
function s = join_lines(lines)
|
||
|
||
if isempty(lines)
|
||
|
||
s = '';
|
||
|
||
return;
|
||
|
||
end
|
||
|
||
s = lines{1};
|
||
|
||
for i = 2:numel(lines)
|
||
|
||
s = [s, sprintf('\n'), lines{i}]; %#ok<AGROW>
|
||
|
||
end
|
||
|
||
end
|
||
|
||
|
||
|
||
function s = json_num(x)
|
||
|
||
s = num2str(x, '%.16g');
|
||
|
||
end
|
||
|
||
|
||
|
||
function s = json_int_array(v)
|
||
|
||
v = v(:)';
|
||
|
||
parts = cell(1, numel(v));
|
||
|
||
for i = 1:numel(v)
|
||
|
||
parts{i} = sprintf('%d', round(v(i)));
|
||
|
||
end
|
||
|
||
s = sprintf('[%s]', join_csv(parts));
|
||
|
||
end
|
||
|
||
|
||
|
||
function s = json_float_array(v)
|
||
|
||
v = v(:)';
|
||
|
||
parts = cell(1, numel(v));
|
||
|
||
for i = 1:numel(v)
|
||
|
||
parts{i} = num2str(v(i), '%.16g');
|
||
|
||
end
|
||
|
||
s = sprintf('[%s]', join_csv(parts));
|
||
|
||
end
|
||
|
||
|
||
|
||
function s = json_str_array(c)
|
||
|
||
parts = cell(1, numel(c));
|
||
|
||
for i = 1:numel(c)
|
||
|
||
parts{i} = sprintf('"%s"', char(c{i}));
|
||
|
||
end
|
||
|
||
s = sprintf('[%s]', join_csv(parts));
|
||
|
||
end
|
||
|
||
|
||
|
||
function s = join_csv(parts)
|
||
|
||
if isempty(parts)
|
||
|
||
s = '';
|
||
|
||
elseif numel(parts) == 1
|
||
|
||
s = parts{1};
|
||
|
||
else
|
||
|
||
s = parts{1};
|
||
|
||
for i = 2:numel(parts)
|
||
|
||
s = [s, ', ', parts{i}]; %#ok<AGROW>
|
||
|
||
end
|
||
|
||
end
|
||
|
||
end
|
||
|