码迷,mamicode.com
首页 > 其他好文 > 详细

高斯面生成程序的简要分析

时间:2015-10-27 15:33:02      阅读:296      评论:0      收藏:0      [点我收藏+]

标签:

#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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!