Example #1
0
bool Jacobian_1to1::calculate(ModelRun &init_model_run, vector<string> numeric_par_names, vector<string> obs_names, ParamTransformSeq &par_transform,
		const ParameterGroupInfo &group_info, const ParameterInfo &ctl_par_info, 
		RunManagerAbstract &run_manager, const PriorInformation &prior_info, set<string> &out_of_bound_par, bool phiredswh_flag, bool calc_init_obs)
{
	int i_run;
	string *par_name;
	double par_value;
	Parameters model_parameters(par_transform.ctl2model_cp(init_model_run.get_ctl_pars()));
	Observations observations(init_model_run.get_obs_template());
	base_numeric_parameters = par_transform.ctl2numeric_cp( init_model_run.get_ctl_pars());
	run_manager.reinitialize(file_manager.build_filename("rnj"));
	const vector<string> &model_par_name_vec = run_manager.get_par_name_vec();
	const vector<string> &obs_name_vec = run_manager.get_obs_name_vec();
	size_t n_par = model_par_name_vec.size();

	failed_parameter_names.clear();
	// compute runs for to jacobain calculation as it is influenced by derivative type( forward or central)
	vector<JacobianRun> del_numeric_par_vec;
	if (calc_init_obs) {
		del_numeric_par_vec.push_back(JacobianRun("", 0));
		run_manager.add_run(model_parameters);
	}
	Parameters new_derivative_pars;
	bool success;
	Parameters base_derivative_parameters = par_transform.numeric2derivative_cp(base_numeric_parameters);
	//Loop through derivative parameters and build the parameter sets necessary for computing the jacobian
	for (auto &i_name : numeric_par_names)
	{
		assert(base_derivative_parameters.find(i_name) != base_derivative_parameters.end());
		vector<JacobianRun> tmp_del_numeric_par_vec;
		double derivative_par_value = base_derivative_parameters.get_rec(i_name);
		success = get_derivative_parameters(i_name, derivative_par_value, par_transform, group_info, ctl_par_info,
			tmp_del_numeric_par_vec, phiredswh_flag);
		if (success && !tmp_del_numeric_par_vec.empty())
		{
			del_numeric_par_vec.insert(del_numeric_par_vec.end(), tmp_del_numeric_par_vec.begin(), tmp_del_numeric_par_vec.end());
			// update changed model parameters in model_parameters
			for (const auto &par : tmp_del_numeric_par_vec)
			{
				Parameters org_pars;
				Parameters new_pars;
				org_pars.insert(make_pair(par.par_name, model_parameters.get_rec(par.par_name)));
				new_pars.insert(make_pair(par.par_name, par.numeric_value));
				par_transform.derivative2model_ip(new_pars);
				for (auto &ipar : new_pars)
				{
					model_parameters[ipar.first] = ipar.second;
				}
				run_manager.add_run(model_parameters);
				for (const auto &ipar : org_pars)
				{
					model_parameters[ipar.first] = ipar.second;
				}
			}
		}
		else 
		{
			failed_parameter_names.insert(i_name);
		}
	}
	ofstream &fout_restart = file_manager.get_ofstream("rst");
	fout_restart << "jacobian_model_runs_begin_group_id " << run_manager.get_cur_groupid() << endl;
	// make model runs
	run_manager.run();
	fout_restart << "jacobian_model_runs_end_group_id " << run_manager.get_cur_groupid() << endl;

	// calculate jacobian
	base_sim_obs_names = obs_names;

	if(matrix.rows() != base_sim_obs_names.size() || matrix.cols() !=numeric_par_names.size())
	{
		matrix.resize(base_sim_obs_names.size(), numeric_par_names.size());
	}
	// initialize prior information
	prior_info_sen.clear();

	unordered_map<string, int> par2col_map = get_par2col_map();
	unordered_map<string, int>::iterator found;
	unordered_map<string, int>::iterator not_found = par2col_map.end();

	i_run = 0;
	// if initial run was performed, get the newly calculated values

	if (calc_init_obs) {
		Parameters tmp_pars;
		Observations tmp_obs;
		bool success = run_manager.get_run(i_run, tmp_pars, tmp_obs);
		if (!success)
		{
			throw(PestError("Error: Base parameter run failed.  Can not compute the Jacobian"));
		}
		par_transform.model2ctl_ip(tmp_pars);
		init_model_run.update_ctl(tmp_pars, tmp_obs);
		++i_run;
	}

	base_numeric_parameters =  par_transform.ctl2numeric_cp(init_model_run.get_ctl_pars());
	// process the parameter pertubation runs
	int nruns = del_numeric_par_vec.size();
	list<pair<ModelRun, double> > run_list;
	base_numeric_par_names.clear();
	ModelRun tmp_model_run = init_model_run;
	int icol = 0;
	vector<string>par_name_vec;
	for(; i_run<nruns; ++i_run)
	{
		par_name = &del_numeric_par_vec[i_run].par_name;
		Parameters tmp_pars;
		Observations tmp_obs;
		bool success = run_manager.get_run(i_run, tmp_pars, tmp_obs);
		if (success)
		{

			par_name_vec.clear();
			par_name_vec.push_back(*par_name);
			par_transform.model2ctl_ip(tmp_pars);
			tmp_model_run.update_ctl(tmp_pars, tmp_obs);
			Parameters numeric_pars(tmp_pars, par_name_vec);
			par_transform.ctl2numeric_ip(numeric_pars);
			par_value = numeric_pars.get_rec(*par_name);
			run_list.push_back(make_pair(tmp_model_run, par_value));
		}

		if(i_run+1>=nruns || *par_name !=  del_numeric_par_vec[i_run+1].par_name)
		{
			if (!run_list.empty())
			{
				base_numeric_par_names.push_back(*par_name);
				double base_numeric_par_value = base_numeric_parameters.get_rec(*par_name);
				run_list.push_front(make_pair(init_model_run, base_numeric_par_value));
				calc_derivative(*par_name, icol, run_list, par_transform, group_info, ctl_par_info, prior_info);
				icol++;
			}
			else
			{
				failed_parameter_names.insert(*par_name);
			}
			run_list.clear();
		}
	}
	matrix.conservativeResize(base_sim_obs_names.size(), base_numeric_par_names.size());
	// clean up
	fout_restart << "jacobian_saved" << endl;
	run_manager.free_memory();
	return true;
}