Class: GSL::Contour2

Inherits:
Object
  • Object
show all
Defined in:
lib/gsl_extras.rb

Constant Summary collapse

VALID_CONNECTIONS =

Edges: 1 __

0 | 4 \ /5  | 2
  | 7 / \ 6 |
    3 __
[[0,4,5,2], [0,4,1], [0,7,3], [0,7,6,2], [0,4,5,6,3],[0,7,6,5,1], [1,4,7,3], [1,5,6,3], [1,5,2], [1,4,7,6,2], [2,6,3],[2,5,4,7,3]]

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(x, y, grid, function = nil) ⇒ Contour2

Returns a new instance of Contour2.

Raises:

  • (ArgumentError)


565
566
567
568
569
570
571
572
# File 'lib/gsl_extras.rb', line 565

def initialize(x, y, grid, function=nil)
	@function = function
	@evaluated = {}
	@x = x; @y=y; @grid=grid
# 			p @grid, @x, @y
	raise ArgumentError.new("Unmatching data sizes: #{x.size}, #{y.size}, #{grid.shape}") unless [x.size, y.size] == grid.shape
	@adaptive = false			
end

Class Method Details

.alloc(x, y, grid, function = nil) ⇒ Object

Create a new Contour object. x and y are vectors of coordinates, and grid is a matrix of values on those coordinates. If a function is given, it will be used to evaluate gridpoints rather than the matrix (though a matrix must still be provided). Provide a function if your contours only cover a small part of the domain and your function is expensive to evaluate.



560
561
562
# File 'lib/gsl_extras.rb', line 560

def self.alloc(x, y, grid, function=nil)
	new(x, y, grid)
end

Instance Method Details

#contours(*values) ⇒ Object

Create a series of contours at the given values. Returns a hash of => array_of_contours. The array_of_contours is a an array of arrays, where each array is a list of [x, y] coordinates along the contour.



582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
# File 'lib/gsl_extras.rb', line 582

def contours(*values)
	(values = (0..values[0]+1).to_a.map{|i| i.to_f * (@grid.max - @grid.min) / ( values[0]+1) + @grid.min}; values.pop; values.shift) if values.size==1 and values[0].kind_of? Integer
	cons = values.inject({}){|hash, val| hash[val] = []; hash}
	get_startpoints(cons)
	#@analysed = {}
	@found = {}
	#p cons
	starts = cons

	cons = values.inject({}){|hash, val| hash[val] = []; hash}
	temp_cons = values.inject({}){|hash, val| hash[val] = []; hash}
	starts.each do |val, arr|
		#p 'arr', arr
		arr.each do |start_con|
		#arr.map{|edges| edges[-1][1].slice(0..1)}.each do |starti, startj|
			starti, startj = start_con[-1][1].slice(0..1)	
			temp_cons[val] = [start_con]
			p 'startj',  starti, startj
			loop do
				starti, startj = trace_contour(val, temp_cons, starti, startj)
				break unless starti and startj
			end
			cons[val].push temp_cons[val][0]
		end
	end
	cons.keys.each{|val| cons[val] = connect_contours(cons[val]);
		cons[val].map!{|con| con.map{|point| point[0]}}}
	
	@last_contours = cons
	gk =  graphkit
	#gk.gp.style = 'data with linespoints'
	gk.data.each{|dk| dk.with = 'lp'}
	gk.gnuplot
	@last_contours
end

#get_startpoints(cons) ⇒ Object



657
658
659
660
661
662
663
664
665
666
667
668
# File 'lib/gsl_extras.rb', line 657

def get_startpoints(cons)	
	[0,((@x.size / 2).floor - 1)-1].each do |i|
		for j in 0...((@y.size / 2).floor - 1)
			analyse_cell(i*2, j*2, cons)
		end
	end
	for i in 0...((@x.size / 2).floor - 1)
	[0,((@y.size / 2).floor - 1)-1].each do |j|
			analyse_cell(i*2, j*2, cons)
		end
	end
end

#graphkit(*args) ⇒ Object

Create a GraphKit object of the contours.



674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
# File 'lib/gsl_extras.rb', line 674

def graphkit(*args)
	if args.size == 0
		conts = @last_contours
	else
		conts = contours(*args)
	end
	graphs = conts.map do |val, cons|
		unless cons[0]
			nil
		else
			(cons.map do |con|
# 				p con
				contour = con.transpose
				kit = CodeRunner::GraphKit.autocreate({x: {data: contour[0]}, y: {data: contour[1], title: val.to_s}})
				kit.data[0].with = "l"
				kit
			end).sum
		end
	end
	graphs.compact.reverse.sum
end

#set_adaptive(func) ⇒ Object

:nodoc:



576
577
578
# File 'lib/gsl_extras.rb', line 576

def set_adaptive(func) # :nodoc:
	@func = func; @adaptive = true
end

#trace_contour(val, cons, starti, startj) ⇒ Object



618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
# File 'lib/gsl_extras.rb', line 618

def trace_contour(val, cons, starti, startj)
			old_start = cons[val][0][0][1]; old_end = cons[val][0][-1][1]
			#p 'old_start', old_start, 'old_end', old_end, 'starti', starti, 'startj', startj
			for delti in -1..1
				for deltj in -1..1
					celli, cellj = [starti + 2 * delti, startj + deltj * 2]
						#unless (@analysed[val] and @analysed[val][[celli, cellj]] ) or celli > (@x.size-3) or cellj >(@y.size - 3) or celli < 0 or cellj < 0
						unless  celli > (@x.size-3) or cellj >(@y.size - 3) or celli < 0 or cellj < 0

				 		#p 'analysing', celli, cellj 
				 		analyse_cell(celli, cellj, cons, val) 
						end

				end
			end
				cons[val] = connect_contours(cons[val])
			#p cons[val]
				new_contour =  cons[val].find{|cont| old_start ==  cont[0][1] or old_end == cont[-1][1]}
				unless new_contour
					cons[val].map!{|con| con.reverse}
				new_contour =  cons[val].find{|cont| old_start ==  cont[0][1] or old_end == cont[-1][1]}
				end
				raise "no new contour" unless new_contour
				cons[val] = [new_contour]
			#p cons[val]
			#newtails  = cons[val].map{|con| con[-1]}
			if cons[val][0][0][1] != old_start 
				return cons[val][0][0][1].slice(0..1)
			elsif cons[val][0][-1][1] != old_end
				return cons[val][0][-1][1].slice(0..1)
			else
				#p cons[val]
				
			p 'old_start', old_start, 'old_end', old_end
				#raise "Could not connect"
				return nil, nil
			end
end