docs: public OptimizationResult getCalibration() throws SolverException {
  
  		Optimizer.ObjectiveFunction objectiveFunction = new Optimizer.ObjectiveFunction() {
  			@Override
  			public void setValues(double[] parameters, double[] values) {
  
  				//We change the parameters of the model
  				CalibratableProcess newModel = model.getCloneForModifiedParameters(parameters);
  				CharacteristicFunctionModel newModelFourier = newModel.getCharacteristicFunctionModel();
  
  				int numberOfMaturities = surface.getMaturities().length;
  				double mats[] = surface.getMaturities();
  
  				QuotingConvention targetConvention = surface.getQuotingConvention();
  
  				ArrayList<Double> vals = new ArrayList<Double>();
  
  				for(int t = 0; t<numberOfMaturities; t++) {
  
  					double[] currentStrikes = surface.getSmile(mats[t]).getStrikes();
  
  					EuropeanOptionSmile newPricer = pricer.getCloneWithModifiedParameters(mats[t],currentStrikes);
  
  					try {
  						Map<String, Function<Double, Double>> currentModelPrices = newPricer.getValue(0.0, newModelFourier);
  
  						for(int i = 0; i<currentStrikes.length;i++) {
  
  							if(targetConvention.equals(QuotingConvention.VOLATILITYLOGNORMAL)) {
  								//we convert prices into lognormal volatilities
  								double forward = surface.getEquityForwardCurve().getDiscountFactor(mats[t]);
  								double optionMaturity =mats[t];
  								double optionStrike = currentStrikes[i];
  								double payoffUnit = surface.getDiscountCurve().getDiscountFactor(mats[t]);
  								double optionValue = currentModelPrices.get("valuePerStrike").apply(optionStrike);
  								vals.add(net.finmath.functions.AnalyticFormulas.blackScholesOptionImpliedVolatility(forward, optionMaturity, optionStrike, payoffUnit, optionValue));
  
  
  							}else if(targetConvention.equals(QuotingConvention.VOLATILITYNORMAL)) {
  								//we convert prices into normal volatilities
  								double forward = surface.getEquityForwardCurve().getDiscountFactor(mats[t]);
  								double optionMaturity =mats[t];
  								double optionStrike = currentStrikes[i];
  								double payoffUnit = surface.getDiscountCurve().getDiscountFactor(mats[t]);
  								double optionValue = currentModelPrices.get("valuePerStrike").apply(optionStrike);
  								vals.add(net.finmath.functions.AnalyticFormulas.bachelierOptionImpliedVolatility(forward, optionMaturity, optionStrike, payoffUnit, optionValue));
  							}else {
  								//just output the prices
  								vals.add(currentModelPrices.get("valuePerStrike").apply(currentStrikes[i]));
  							}
  
  						}
  					} catch (CalculationException e) {
  						e.printStackTrace();
  					}
  
  				}
  				for(int i = 0; i<values.length; i++) {values[i] = vals.get(i);}
  			}
  		};
  
  		Optimizer optimizer = optimizerFactory.getOptimizer(
  				objectiveFunction,
  				initialParameters,
  				lowerBound,
  				upperBound,
  				parameterStep,
  				formatTargetValuesForOptimizer() /* targetValues */);
  
  
  		optimizer.run();
  
  		ArrayList<String> calibrationOutput = outputCalibrationResult(optimizer.getBestFitParameters());
  
  		CalibratableProcess calibratedModel = model.getCloneForModifiedParameters(optimizer.getBestFitParameters());
  
  		return new OptimizationResult(calibratedModel,optimizer.getBestFitParameters(),optimizer.getIterations(),optimizer.getRootMeanSquaredError(),calibrationOutput);
  	}