from pyopus.evaluator.aggregate import formatParameters
from pyopus.design.cbd import CornerBasedDesign
from pyopus.parallel.cooperative import cOS

heads = {
	'opus': {
		'simulator': 'SpiceOpus', 
		'settings': {
			'debug': 0
		},
		'moddefs': {
			'def':  { 'file': 'bjtamp.inc' }, 
		}, 
		'options': {
		}, 
		'params': {
		}
	}
}

analyses = {
	'dc': {
		'head': 'opus', 
		'modules': [ 'def' ], 
		'command': "dc(-100e-6, 100e-6, 'lin', 100, 'i1', 'dc')"
	}, 
}

# Define performance measures, dependencies, and design requirements (lower and upper bounds)
# Gain should be above 20kV/A, nonlinearity should be below 80mV
measures = {
	'gain': {
		'analysis': 'dc', 
		'expression': """
# Get response
x, y = scale(), v('out')

# Construct line from first to last point, extract gain
gain=(y[-1]-y[0])/(x[-1]-x[0])
""", 
		'lower':20e3
	}, 
	'nonlinearity': {
		'analysis': 'dc', 
		'expression': """
# Get response
x, y = scale(), v('out')

# Construct line from first to last point
ylin=y[0]+(x-x[0])*(y[-1]-y[0])/(x[-1]-x[0])

# Maximal deviation from line
nonlinearity=(np.abs(y-ylin)).max()
""", 
		'upper': 80e-3
	}, 
}

# Design parameters, lower bounds, upper bounds, and initial values
designParams={
	'r1': {
		'lo':	5e3, 
		'hi':	50e3, 
		'init': 45e3,
	}, 
	'r2': {
		'lo':	20e3, 
		'hi':	200e3, 
		'init': 195e3,
	}, 
}

# Nominal corner
corners={
	'nominal': {
		'heads': ['opus'], 
		'params': {
			'vcc': 12, 
			'temperature': 25
		}, 
		'modules': []
	}
}
		
if __name__=='__main__':
	# Uncomment if you want to run it in parallel using MPI
	from pyopus.parallel.mpi import MPI
	cOS.setVM(MPI())
	
	# Design the circuit so that it satisfies the design requirements in nominal corner
	designer=CornerBasedDesign(
		designParams, heads, analyses, measures, corners, 
		initial={ name: value['init'] for name, value in designParams.items() }, 
		method='global', 
		debug=1
	)
	
	# Run optimization
	atDesign, aggregator, analysisCount = designer()
	
	# Print result
	print(formatParameters(atDesign))
	print(aggregator.formatResults())
	
	# Finalize cOS parallel environment
	cOS.finalize()
	
