标签:
#ifndef _GAUSS_HPP_
#define _GAUSS_HPP_
#include "config.h"
#include "gauss.h"
#include "geometry/cumath.h"
#include "layout/layout.h"
#include "utils/floatnum.h"
#include "utils/logger.h"
#include <iostream>
void gaussian_surface::surface_block_index::insert(const surface_block &bgs) {
for (const surface_block &old : _list) {
assert(old.block != bgs.block);
if ( !cross(old.shape.box, bgs.shape.box) ) continue;
_index.insert({std::cref(bgs), std::cref(old)});
_index.insert({std::cref(old), std::cref(bgs)});
}
_list.push_back(bgs);
}
int gaussian_surface::surface_block_index::count(const point_t &pt,
const surface_piece &piece) const {
int cnt = 1;
auto blks = sea::val_view(_index.equal_range(piece.from));
for (const surface_block &g : blks) {
assert(g.block != piece.from.block);
space_t d = manhattan_distance(pt, g.shape);
if ( d > SS_ZERO ) continue;
if ( d < SS_ZERO ) return -1;
if ( piece.drc == sdim::END ) {
auto pics = sea::val_view(g.pieces.equal_range(piece.normal));
for (const surface_piece &pic : pics) {
if ( is_on(pt, pic.plane) ) return -1;
}
} else if ( is_positive(piece.drc) ) {
udim ud = abs(piece.drc);
if ( g.shape.box.min.w(ud) == pt.w(ud) ) return -1;
} else {
udim ud = abs(piece.drc);
if ( g.shape.box.max.w(ud) == pt.w(ud) ) return -1;
}
++cnt;
}
return cnt;
}
gauss_point gaussian_surface::get_random_point(Sea::Random &rand) const {
gauss_point result;
result.gtried = 0;
result.sumpdf = 0.0;
while (true) {
++result.gtried;
size_t id = Sea::select(_areas, _areas + _pieces.size(), rand.value());
const surface_piece &pic = _pieces[id];
static constexpr double GN = 64.0;
double p = (floor(rand.value() * GN) + 0.5) / GN;
double q = (floor(rand.value() * GN) + 0.5) / GN;
result.point = select_point(pic.plane, p, q);
if ( pic.from.overflow &&
!contains(_layout.window().space, result.point) ) {
continue;
}
int rpt = _index.count(result.point, pic);
if ( rpt < 0 || (double)rpt * rand.value() > 1.0 ) {
continue;
}
size_t rid = _layout.layers().locate(result.point.z);
diel_t diel;
if ( dielectric_layers::is_diel_id(rid) ) {
diel = _layout.layers().diel_val(rid);
} else {
size_t f = dielectric_layers::face_to_above_diel(rid);
diel = _layout.layers().diel_val(f-1);
diel = (diel + _layout.layers().diel_val(f)) / 2;
}
double pdf = pdftype(diel, pic.from.dist);
result.sumpdf += pdf;
if ( _maxpdf * rand.value() > pdf ) {
continue;
}
result.drc = pic.drc;
result.dist = pic.from.dist;
result.normal = pic.normal;
result.block = pic.from.block;
result.weight = get_diel(diel) / pdf;
break;
}
if ( result.drc == sdim::END ) {
int x = result.normal.x;
int y = result.normal.y;
if ( rand.value() * (double)(abs(x) + abs(y)) < (double)abs(x) ) {
result.drc = x > 0 ? sdim::PX : sdim::NX;
} else {
result.drc = y > 0 ? sdim::PY : sdim::NY;
}
}
return result;
}
void gaussian_surface::initialize(const wire_net *master) {
for (const wire_block *b : master->blocks()) {
generate_bgs(b);
}
for (surface_piece &p : _pieces) {
if ( p.drc != sdim::END ) continue;
normal_t n = p.normal;
n = normal_t(-n.x, -n.y);
p.from.pieces.insert({n, std::cref(p)});
}
for (surface_block &b : _surface_blocks) {
if ( _layout.window().type == circuit_layout::boundary::NEUMANN ) {
b.overflow = !contains(_layout.window().space, b.shape.box);
}
_index.insert(b);
}
size_t n = _pieces.size();
assert(n != 0);
_areas = new double [n];
for (size_t i = 0; i < n; ++i) {
_area += area_of(_pieces[i].plane).val();
_areas[i] = _area;
}
for (size_t i = 0; i < n; ++i) {
_areas[i] /= _area;
}
assert(Sea::FloatNum::equal(_areas[n-1], 1.0));
_areas[n-1] = 1.0;
space_t min_dist = SS_MAX;
diel_t max_diel = ZERO_DIEL;
for (const surface_block &blk : _surface_blocks) {
min_dist = std::min(min_dist, blk.dist);
}
for (size_t m : _layout.layers().diel_ids()) {
max_diel = std::max(max_diel, _layout.layers().diel_val(m));
}
_maxpdf = pdftype(max_diel, min_dist);
}
class update_dist {
private:
const shape_t &_shape;
bool _is_box;
point2d_t hps1[4];
size_t nhp1;
public:
space_t dist;
update_dist(const shape_t &s, space_t d):
_shape(s), _is_box(is_box(s)), nhp1(get_hpoints(s, hps1)), dist(d) {}
void update(const shape_t &other) {
space_t xd = distance(_shape.box, other.box, udim::X);
if ( !(xd < dist) ) return;
space_t yd = distance(_shape.box, other.box, udim::Y);
if ( !(yd < dist) ) return;
space_t zd = distance(_shape.box, other.box, udim::Z);
if ( !(zd < dist) ) return;
if ( _is_box && is_box(other) ) {
dist = std::max(std::max(xd, yd), zd);
return;
}
space_t hd = dist;
for (size_t i = 0; i < nhp1; ++i) {
hd = std::min(hd, horizontal_manhattan_distance(hps1[i], other));
}
point2d_t hps2[4];
size_t nhp2 = get_hpoints(other, hps2);
for (size_t i = 0; i < nhp2; ++i) {
hd = std::min(hd, horizontal_manhattan_distance(hps2[i], _shape));
}
dist = std::max(hd, zd);
}
static bool is_box(const shape_t &s) {
return s.code == shape_code::CUBOID || s.code == shape_code::CYLIND;
}
};
void gaussian_surface::generate_bgs(const wire_block *mblk) {
const shape_t &s1 = mblk->shape();
space_t dist = size_of(s1.box) * 20;
dist = std::min(dist, _layout.wire_width() * 100);
dist = std::min(dist, get_dist_by_layer(s1.box));
dist = std::min(dist, get_dist_by_window(s1.box));
update_dist updater = update_dist(s1, dist);
for (const wire_block *b : _layout.blocks()) {
if ( b->net() == mblk->net() ) continue;
updater.update(b->shape());
}
dist = updater.dist / 2;
if (dist <= SS_ZERO) {
log_error("Error: the master net is touched by other net!\n").nl();
exit(EXIT_FAILURE);
}
switch ( s1.code ) {
case shape_code::CUBOID:
generate_pieces_for_cuboid(mblk, dist);
break;
case shape_code::CYLIND:
generate_pieces_for_cylind(mblk, dist);
break;
case shape_code::NPRISM:
generate_pieces_for_nprism(mblk, dist);
break;
default:
assert(false);
}
}
void gaussian_surface::generate_pieces_for_cuboid(const wire_block *mblk, space_t dist) {
cuboid_t surface = expand(mblk->shape().box, dist);
_surface_blocks.emplace_back(shape_t(surface), dist, mblk);
for (size_t id = 0; id < SIGNED_DIMENSION; ++id) {
sdim sd = (sdim)id;
udim ud = abs(sd);
rectangle_t rc;
rc.base = surface.min;
if ( is_positive(sd) )
rc.base.w(ud, surface.max.w(ud));
rc.nlen = surface.wlen(next(ud));
rc.plen = surface.wlen(prev(ud));
rc.drc = sd;
_pieces.emplace_back(plane_t(rc), sd, _surface_blocks.back());
}
}
void gaussian_surface::generate_pieces_for_cylind(const wire_block *m, space_t d) {
generate_pieces_for_cuboid(m, d);
}
void gaussian_surface::generate_pieces_for_nprism(const wire_block *mblk, space_t dist) {
const nprism_t &p = mblk->shape().nprism();
std::vector<normal_t> nvs(2*p.npts+1);
for (size_t i = 0; i < p.npts; ++i) {
point2d_t s = p.vertex[i], t = p.next_vertex(i);
vector2d_t e = minus(t, s);
auto n = normal_t(sign(e.y), -sign(e.x));
if ( n.x == 0 || n.y == 0 ) {
nvs[2*i+1] = normal_t(n.y + n.x, n.y - n.x);
nvs[2*i+2] = normal_t(n.x - n.y, n.x + n.y);
} else {
nvs[2*i+1] = nvs[2*i+2] = n;
}
}
nvs[0] = nvs[2*p.npts];
point2d_t vs[12];
size_t nv = 0;
for (size_t i = 0; i < p.npts; ++i) {
normal_t n1 = nvs[2*i], n2 = nvs[2*i+1];
vs[nv++] = move(p.vertex[i], dist * n1.x, dist * n1.y);
if ( eq(n1, n2) ) continue;
if ( eq(plus(n1, n2), normal_t(0, 0)) ) {
normal_t n = normal_t(-n1.y, n1.x);
vs[nv++] = move(p.vertex[i], dist * n.x, dist * n.y);
}
vs[nv++] = move(p.vertex[i], dist * n2.x, dist * n2.y);
}
nprism_t surface = nprism_t(nv, p.minz - dist, p.maxz + dist);
assert( nv <= nprism_t::NPTS );
std::copy_n(vs, nv, surface.vertex);
_surface_blocks.emplace_back(shape_t(surface), dist, mblk);
for (size_t i = 1; i < surface.npts - 1; ++i) {
triangle_t tr = triangle_t(surface.minz, surface.vertex[0],
surface.vertex[i], surface.vertex[i+1], sdim::NZ);
_pieces.emplace_back(plane_t(tr), sdim::NZ, _surface_blocks.back());
tr.drc = sdim::PZ;
tr.zpos = surface.maxz;
_pieces.emplace_back(plane_t(tr), sdim::PZ, _surface_blocks.back());
}
for (size_t i = 0; i < surface.npts; ++i) {
// 添加侧面
point2d_t s = surface.vertex[i], t = surface.next_vertex(i);
if ( s.x == t.x ) {
// 两个点的 x 轴相等, 说明面平行于 yOz 平面, 为长方形面
rectangle_t rc;
rc.base = point_t(s.x, std::min(s.y, t.y), surface.minz);
rc.plen = surface.maxz - surface.minz;
rc.nlen = sea::abs(t.y - s.y);
rc.drc = s.y < t.y ? sdim::PX : sdim::NX;
_pieces.emplace_back(plane_t(rc), rc.drc, _surface_blocks.back());
} else if ( s.y == t.y ) {
rectangle_t rc;
rc.base = point_t(std::min(s.x, t.x), s.y, surface.minz);
rc.nlen = surface.maxz - surface.minz;
rc.plen = sea::abs(t.x - s.x);
rc.drc = s.x < t.x ? sdim::NY : sdim::PY;
_pieces.emplace_back(plane_t(rc), rc.drc, _surface_blocks.back());
} else {
incline_t ic;
ic.base = point_t(s.x, s.y, surface.minz);
ic.length = minus(t, s);
ic.height = surface.maxz - surface.minz;
double x = +ic.length.y.val();
double y = -ic.length.x.val();
double l = 32768.0 / sqrt(x*x + y*y);
int nx = (int)round(x * l);
int ny = (int)round(y * l);
_pieces.emplace_back(plane_t(ic), normal_t(nx, ny), _surface_blocks.back());
}
}
}
space_t gaussian_surface::get_dist_by_layer(const cuboid_t &box) const {
const dielectric_layers &layers = _layout.layers();
if ( layers.is_single() ) {
return SS_MAX;
} else if ( _config.layout.multi_dielectric ==
configure::layout_arg::APPROX ) {
return SS_MAX;
}
size_t delta = (_config.layout.multi_dielectric ==
configure::layout_arg::TWO ||
_config.layout.multi_dielectric == configure::layout_arg::APPROX2)
? 2 : 3;
size_t uid = layers.locate(box.min.z);
if ( dielectric_layers::is_diel_id(uid) ) {
uid = dielectric_layers::diel_to_above_face(uid);
}
space_t ud = (box.min.z - layers.face_pos(uid - delta)) * 2;
size_t vid = layers.locate(box.max.z, uid - 1);
if ( dielectric_layers::is_diel_id(vid) ) {
vid = dielectric_layers::diel_to_below_face(vid);
}
space_t vd = (layers.face_pos(vid + delta) - box.max.z) * 2;
return std::min(ud, vd);
}
space_t gaussian_surface::get_dist_by_window(const cuboid_t &box) const {
if ( _layout.window().type == circuit_layout::boundary::NEUMANN ) {
return SS_MAX;
}
const cuboid_t &win = _layout.window().space;
point_t d = minimal(minus(win.max, box.max), minus(box.min, win.min));
return std::min(std::min(d.x, d.y), d.z);
}
double gaussian_surface::pdftype(diel_t diel, space_t dist) const {
switch ( _config.gauss.type ) {
case configure::gauss_arg::UNIFORM: return 1.0;
case configure::gauss_arg::DEFAULT:
case configure::gauss_arg::DIEL: return get_diel(diel);
case configure::gauss_arg::DIST: return 1.0 / ss2d(dist);
case configure::gauss_arg::BOTH: return get_diel(diel) / ss2d(dist);
}
assert(false);
return 0.0;
}
#endif // _GAUSS_HPP_
标签:
原文地址:http://my.oschina.net/donngchao/blog/522661