<commit_before>// Program name: atomic++/Prad.cpp
// Author: Thomas Body
// Author email: tajb500@york.ac.uk
// Date of creation: 17 July 2017
//
// Program function: output the radiated power (Prad)
//                   by using OpenADAS rates on output JSON from SD1D run
//
// Based on the TBody/atomic1D code, which is in turn based on the cfe316/atomic code
//

// Include declarations
#include <ostream>
#include <cstdio> //For print formatting (printf, fprintf, sprintf, snprintf)

#include "atomicpp/ImpuritySpecies.hpp"
#include "atomicpp/RateCoefficient.hpp"
#include "atomicpp/SD1DData.hpp"
#include "atomicpp/RateEquations.hpp"

#include "atomicpp/ExternalModules/json.hpp"
using json = nlohmann::json;

// extern const double eV_to_J; //Conversion factor between electron-volts and joules (effective units J/eV)
// extern const double amu_to_kg; ////Conversion factor between atomic-mass-units and kilograms (effective units kg/amu)

//Only used for getting guess values for the impurity ionisation-stage densities -- not required for final code
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////// NOT FOR FINAL SIMULATION CODE //////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<double> computeIonisationDistribution(atomicpp::ImpuritySpecies& impurity, double Te, double Ne, double Nz, double Nn){

	int Z = impurity.get_atomic_number();
	std::vector<double> iz_stage_distribution(Z+1);

	// std::set GS density equal to 1 (arbitrary)
	iz_stage_distribution[0] = 1;
	double sum_iz = 1;

	// Loop over 0, 1, ..., Z-1
	// Each charge state is std::set in terms of the density of the previous
	for(int k=0; k<Z; ++k){
		// Ionisation
		// Get the atomicpp::RateCoefficient from the rate_coefficient std::map (atrribute of impurity)
		std::shared_ptr<atomicpp::RateCoefficient> iz_rate_coefficient = impurity.get_rate_coefficient("ionisation");
		// Evaluate the atomicpp::RateCoefficient at the point
		double k_iz_evaluated = iz_rate_coefficient->call0D(k, Te, Ne);

		// Recombination
		// Get the atomicpp::RateCoefficient from the rate_coefficient std::map (atrribute of impurity)
		std::shared_ptr<atomicpp::RateCoefficient> rec_rate_coefficient = impurity.get_rate_coefficient("recombination");
		// Evaluate the atomicpp::RateCoefficient at the point
		double k_rec_evaluated = rec_rate_coefficient->call0D(k, Te, Ne);

		// The ratio of ionisation from the (k)th stage and recombination from the (k+1)th std::sets the equilibrium densities
		// of the (k+1)th stage in terms of the (k)th (since R = Nz * Ne * rate_coefficient) N.b. Since there is no
		// ionisation from the bare nucleus, and no recombination onto the neutral (ignoring anion formation) the 'k'
		// value of ionisation coeffs is shifted down  by one relative to the recombination coeffs - therefore this
		// evaluation actually gives the balance

		iz_stage_distribution[k+1] = iz_stage_distribution[k] * (k_iz_evaluated/k_rec_evaluated);
		sum_iz += iz_stage_distribution[k+1];
	}

	// # Normalise such that the sum over all ionisation stages is '1' at all points
	for(int k=0; k<=Z; ++k){
		iz_stage_distribution[k] = iz_stage_distribution[k] / sum_iz;
	}
	return iz_stage_distribution;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////// NOT FOR FINAL SIMULATION CODE //////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int main(){
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//Setup the atomicpp::ImpuritySpecies object
	const std::string expt_results_json="sd1d-case-05.json";
	std::string impurity_symbol="c";
	std::string hydrogen_symbol="h";

	atomicpp::ImpuritySpecies impurity(impurity_symbol);
	atomicpp::ImpuritySpecies hydrogen(hydrogen_symbol);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Process the expt_results_json to extract
	// 	density(s) 					= electron density (in m^-3)
	// 	temperature(s)				= electron/ion temperature (in eV)
	// 	neutral_fraction(s)			= neutral density/electron density (no units)
	// where s is 1D distance index. Time is already contracted (using final time-step)
	// Second argument is impurity fraction
	atomicpp::SD1DData experiment(expt_results_json, 1e-2);
	// N.b. This is only for training the data

	//Cast the SD1D data into a form which is like how the function will be called by SD1D
	//This is all not required for SD1D -- it's just to train the code with reasonable numbers
		// const double mz = impurity.get_mass(); //amu

		int constant_position_index = 0;
		double Te = experiment.get_temperature()[constant_position_index];
		double Ne = experiment.get_density()[constant_position_index];
		double Vi = 3.10080599e-01 * 69205.6142373; //Picked random values from SD1D output. Using rho_s0 * Omega_ci to normalise (probably wrong!!)
		double Vn = 1.32440666e-01 * 69205.6142373; //Picked random values from SD1D output. Using rho_s0 * Omega_ci to normalise (probably wrong!!)
		double neutral_fraction = experiment.get_neutral_fraction()[constant_position_index];
		double Nn = Ne * neutral_fraction;

		double Nz = experiment.get_impurity_density()[constant_position_index];
		// Compute the iz-stage-distribution to create the Nzk (charged-resolved impurity) density std::vector
		std::vector<double> iz_stage_distribution = computeIonisationDistribution(impurity, Te, Ne, Nz, Nn);
		std::vector<double> Nzk(impurity.get_atomic_number()+1);
		for(int k=0; k<=impurity.get_atomic_number(); ++k){
			// Use the plasma temperature, and then add a scaling based on the charge so that there's different velocities for each charge
			// (so that momentum transfer results in an observable effect)
			Nzk[k] = Nz * iz_stage_distribution[k];
			// std::printf("Nzk^%d: %e \n", k, Nzk[k]); //To train python data
		}
		std::vector<double> Vzk(impurity.get_atomic_number()+1);
		for(int k=0; k<=impurity.get_atomic_number(); ++k){
			Vzk[k] = Vi;
			// sqrt(2 * Te * eV_to_J / (mz * amu_to_kg));
			// std::printf("Vz_i^(%i):  %+.2e [m/s]\n",k ,Vzk[k]);
		}

		std::vector<double> Nhk(hydrogen.get_atomic_number()+1);
		Nhk[0] = Nn;
		Nhk[1] = Ne;
		std::vector<double> Vhk(hydrogen.get_atomic_number()+1);
		for(int k=0; k<=hydrogen.get_atomic_number(); ++k){
			Vhk[k] = Vi;
		}
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Time dependant solver code

	atomicpp::RateEquations impurity_derivatives(impurity); //Organised as a atomicpp::RateEquations object for cleanliness
	impurity_derivatives.setThresholdDensity(0); //Density threshold - ignore ionisation stages which don't have at least this density
	impurity_derivatives.setDominantIonMass(1.0); //Dominant ion mass in amu, for the stopping time calculation

	atomicpp::DerivStruct derivative_struct = impurity_derivatives.computeDerivs(6000, 1e19, Vi, Nn, Vn, Nzk, Vzk);
	// double Pcool             = derivative_struct.Pcool;
	// double Prad              = derivative_struct.Prad;
	// std::vector<double> dNzk = derivative_struct.dNzk;
	// std::vector<double> F_zk = derivative_struct.F_zk;
	// double dNe               = derivative_struct.dNe;
	// double F_i               = derivative_struct.F_i;
	// double dNn               = derivative_struct.dNn;
	// double F_n               = derivative_struct.F_n;

	std::printf("\nDerivatives for %s\n",impurity.get_name().c_str());
	impurity_derivatives.printDerivativeStruct(derivative_struct);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	// atomicpp::RateEquations hydrogen_derivatives(hydrogen); //Organised as a atomicpp::RateEquations object for cleanliness
	// hydrogen_derivatives.setThresholdDensity(0.0); //Density threshold - ignore ionisation stages which don't have at least this density

	// atomicpp::DerivStruct derivative_struct_H = hydrogen_derivatives.computeDerivsHydrogen(6309.573445, 1e19, Nhk, Vhk);

	// std::printf("\nDerivatives for %s\n",hydrogen.get_name().c_str());
	// hydrogen_derivatives.printDerivativeStruct(derivative_struct_H);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Comparison to Post PSI
	// Ne = 1e18;
	// Te = 6;
	// Nn = 0;
	// total_power = computeRadiatedPower(impurity, Te, Ne, Nz, Nn);
	// std::cout << "Comparison to PSI paper:" << total_power << "W/m3" << std::endl;
	// std::cout << "Comparison to PSI paper:" << total_power/(Nz*Ne) << "Wm3" << std::endl;

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// std::pair<int, double> Te_interp, Ne_interp;
	// Te_interp = findSharedInterpolation(impurity.get_rate_coefficient("blank")->get_log_temp(), Te);
	// Ne_interp = findSharedInterpolation(impurity.get_rate_coefficient("blank")->get_log_dens(), Ne);

	// int Z = impurity.get_atomic_number();
	// const double eV_to_J = 1.60217662e-19; //J per eV

	// if (impurity.get_has_charge_exchange()){
	// 	std::vector<double> dNn_from_stage(impurity.get_atomic_number(), 0.0);
	// 	std::vector<double>   cx_rec_to_below(Z+1, 0.0);
	// 	std::vector<double> cx_rec_from_above(Z+1, 0.0);

	// 	std::shared_ptr<atomicpp::RateCoefficient> cx_recombination_coefficient = impurity.get_rate_coefficient("cx_rec");
	// 	std::shared_ptr<atomicpp::RateCoefficient> cx_power_coefficient = impurity.get_rate_coefficient("cx_power");

	// 	for(int k=0; k < Z; ++k){//N.b. iterating over all data indicies of the rate coefficient, hence the <
	// 		// m^-3 s^-1
	// 		double cx_recombination_coefficient_evaluated = cx_recombination_coefficient->call0D(k, Te_interp, Ne_interp);
	// 		double cx_recombination_rate = cx_recombination_coefficient_evaluated * Nn * Nzk[k+1];

	// 		// W m^-3
	// 		double cx_power_coefficient_evaluated = cx_power_coefficient->call0D(k, Te_interp, Ne_interp);
	// 		double cx_power_rate = cx_power_coefficient_evaluated * Nn * Nzk[k+1] / eV_to_J;

	// 		std::printf("cx: %e [m^-3 s^-1], cx_power: %e [eV m^-3 s^-1], per transition: %e [eV] \n", cx_recombination_rate, cx_power_rate, cx_power_rate/cx_recombination_rate);
	// 	}
	// }

}

<commit_msg>Changed Prad back to sensible Te<commit_after>// Program name: atomic++/Prad.cpp
// Author: Thomas Body
// Author email: tajb500@york.ac.uk
// Date of creation: 17 July 2017
//
// Program function: output the radiated power (Prad)
//                   by using OpenADAS rates on output JSON from SD1D run
//
// Based on the TBody/atomic1D code, which is in turn based on the cfe316/atomic code
//

// Include declarations
#include <ostream>
#include <cstdio> //For print formatting (printf, fprintf, sprintf, snprintf)

#include "atomicpp/ImpuritySpecies.hpp"
#include "atomicpp/RateCoefficient.hpp"
#include "atomicpp/SD1DData.hpp"
#include "atomicpp/RateEquations.hpp"

#include "atomicpp/ExternalModules/json.hpp"
using json = nlohmann::json;

// extern const double eV_to_J; //Conversion factor between electron-volts and joules (effective units J/eV)
// extern const double amu_to_kg; ////Conversion factor between atomic-mass-units and kilograms (effective units kg/amu)

//Only used for getting guess values for the impurity ionisation-stage densities -- not required for final code
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////// NOT FOR FINAL SIMULATION CODE //////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<double> computeIonisationDistribution(atomicpp::ImpuritySpecies& impurity, double Te, double Ne, double Nz, double Nn){

	int Z = impurity.get_atomic_number();
	std::vector<double> iz_stage_distribution(Z+1);

	// std::set GS density equal to 1 (arbitrary)
	iz_stage_distribution[0] = 1;
	double sum_iz = 1;

	// Loop over 0, 1, ..., Z-1
	// Each charge state is std::set in terms of the density of the previous
	for(int k=0; k<Z; ++k){
		// Ionisation
		// Get the atomicpp::RateCoefficient from the rate_coefficient std::map (atrribute of impurity)
		std::shared_ptr<atomicpp::RateCoefficient> iz_rate_coefficient = impurity.get_rate_coefficient("ionisation");
		// Evaluate the atomicpp::RateCoefficient at the point
		double k_iz_evaluated = iz_rate_coefficient->call0D(k, Te, Ne);

		// Recombination
		// Get the atomicpp::RateCoefficient from the rate_coefficient std::map (atrribute of impurity)
		std::shared_ptr<atomicpp::RateCoefficient> rec_rate_coefficient = impurity.get_rate_coefficient("recombination");
		// Evaluate the atomicpp::RateCoefficient at the point
		double k_rec_evaluated = rec_rate_coefficient->call0D(k, Te, Ne);

		// The ratio of ionisation from the (k)th stage and recombination from the (k+1)th std::sets the equilibrium densities
		// of the (k+1)th stage in terms of the (k)th (since R = Nz * Ne * rate_coefficient) N.b. Since there is no
		// ionisation from the bare nucleus, and no recombination onto the neutral (ignoring anion formation) the 'k'
		// value of ionisation coeffs is shifted down  by one relative to the recombination coeffs - therefore this
		// evaluation actually gives the balance

		iz_stage_distribution[k+1] = iz_stage_distribution[k] * (k_iz_evaluated/k_rec_evaluated);
		sum_iz += iz_stage_distribution[k+1];
	}

	// # Normalise such that the sum over all ionisation stages is '1' at all points
	for(int k=0; k<=Z; ++k){
		iz_stage_distribution[k] = iz_stage_distribution[k] / sum_iz;
	}
	return iz_stage_distribution;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////// NOT FOR FINAL SIMULATION CODE //////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int main(){
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//Setup the atomicpp::ImpuritySpecies object
	const std::string expt_results_json="sd1d-case-05.json";
	std::string impurity_symbol="c";
	std::string hydrogen_symbol="h";

	atomicpp::ImpuritySpecies impurity(impurity_symbol);
	atomicpp::ImpuritySpecies hydrogen(hydrogen_symbol);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Process the expt_results_json to extract
	// 	density(s) 					= electron density (in m^-3)
	// 	temperature(s)				= electron/ion temperature (in eV)
	// 	neutral_fraction(s)			= neutral density/electron density (no units)
	// where s is 1D distance index. Time is already contracted (using final time-step)
	// Second argument is impurity fraction
	atomicpp::SD1DData experiment(expt_results_json, 1e-2);
	// N.b. This is only for training the data

	//Cast the SD1D data into a form which is like how the function will be called by SD1D
	//This is all not required for SD1D -- it's just to train the code with reasonable numbers
		// const double mz = impurity.get_mass(); //amu

		int constant_position_index = 0;
		double Te = experiment.get_temperature()[constant_position_index];
		double Ne = experiment.get_density()[constant_position_index];
		double Vi = 3.10080599e-01 * 69205.6142373; //Picked random values from SD1D output. Using rho_s0 * Omega_ci to normalise (probably wrong!!)
		double Vn = 1.32440666e-01 * 69205.6142373; //Picked random values from SD1D output. Using rho_s0 * Omega_ci to normalise (probably wrong!!)
		double neutral_fraction = experiment.get_neutral_fraction()[constant_position_index];
		double Nn = Ne * neutral_fraction;

		double Nz = experiment.get_impurity_density()[constant_position_index];
		// Compute the iz-stage-distribution to create the Nzk (charged-resolved impurity) density std::vector
		std::vector<double> iz_stage_distribution = computeIonisationDistribution(impurity, Te, Ne, Nz, Nn);
		std::vector<double> Nzk(impurity.get_atomic_number()+1);
		for(int k=0; k<=impurity.get_atomic_number(); ++k){
			// Use the plasma temperature, and then add a scaling based on the charge so that there's different velocities for each charge
			// (so that momentum transfer results in an observable effect)
			Nzk[k] = Nz * iz_stage_distribution[k];
			// std::printf("Nzk^%d: %e \n", k, Nzk[k]); //To train python data
		}
		std::vector<double> Vzk(impurity.get_atomic_number()+1);
		for(int k=0; k<=impurity.get_atomic_number(); ++k){
			Vzk[k] = Vi;
			// sqrt(2 * Te * eV_to_J / (mz * amu_to_kg));
			// std::printf("Vz_i^(%i):  %+.2e [m/s]\n",k ,Vzk[k]);
		}

		std::vector<double> Nhk(hydrogen.get_atomic_number()+1);
		Nhk[0] = Nn;
		Nhk[1] = Ne;
		std::vector<double> Vhk(hydrogen.get_atomic_number()+1);
		for(int k=0; k<=hydrogen.get_atomic_number(); ++k){
			Vhk[k] = Vi;
		}
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Time dependant solver code

	atomicpp::RateEquations impurity_derivatives(impurity); //Organised as a atomicpp::RateEquations object for cleanliness
	impurity_derivatives.setThresholdDensity(0); //Density threshold - ignore ionisation stages which don't have at least this density
	impurity_derivatives.setDominantIonMass(1.0); //Dominant ion mass in amu, for the stopping time calculation

	atomicpp::DerivStruct derivative_struct = impurity_derivatives.computeDerivs(50, 1e19, Vi, Nn, Vn, Nzk, Vzk);
	// double Pcool             = derivative_struct.Pcool;
	// double Prad              = derivative_struct.Prad;
	// std::vector<double> dNzk = derivative_struct.dNzk;
	// std::vector<double> F_zk = derivative_struct.F_zk;
	// double dNe               = derivative_struct.dNe;
	// double F_i               = derivative_struct.F_i;
	// double dNn               = derivative_struct.dNn;
	// double F_n               = derivative_struct.F_n;

	std::printf("\nDerivatives for %s\n",impurity.get_name().c_str());
	impurity_derivatives.printDerivativeStruct(derivative_struct);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	// atomicpp::RateEquations hydrogen_derivatives(hydrogen); //Organised as a atomicpp::RateEquations object for cleanliness
	// hydrogen_derivatives.setThresholdDensity(0.0); //Density threshold - ignore ionisation stages which don't have at least this density

	// atomicpp::DerivStruct derivative_struct_H = hydrogen_derivatives.computeDerivsHydrogen(6309.573445, 1e19, Nhk, Vhk);

	// std::printf("\nDerivatives for %s\n",hydrogen.get_name().c_str());
	// hydrogen_derivatives.printDerivativeStruct(derivative_struct_H);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Comparison to Post PSI
	// Ne = 1e18;
	// Te = 6;
	// Nn = 0;
	// total_power = computeRadiatedPower(impurity, Te, Ne, Nz, Nn);
	// std::cout << "Comparison to PSI paper:" << total_power << "W/m3" << std::endl;
	// std::cout << "Comparison to PSI paper:" << total_power/(Nz*Ne) << "Wm3" << std::endl;

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// std::pair<int, double> Te_interp, Ne_interp;
	// Te_interp = findSharedInterpolation(impurity.get_rate_coefficient("blank")->get_log_temp(), Te);
	// Ne_interp = findSharedInterpolation(impurity.get_rate_coefficient("blank")->get_log_dens(), Ne);

	// int Z = impurity.get_atomic_number();
	// const double eV_to_J = 1.60217662e-19; //J per eV

	// if (impurity.get_has_charge_exchange()){
	// 	std::vector<double> dNn_from_stage(impurity.get_atomic_number(), 0.0);
	// 	std::vector<double>   cx_rec_to_below(Z+1, 0.0);
	// 	std::vector<double> cx_rec_from_above(Z+1, 0.0);

	// 	std::shared_ptr<atomicpp::RateCoefficient> cx_recombination_coefficient = impurity.get_rate_coefficient("cx_rec");
	// 	std::shared_ptr<atomicpp::RateCoefficient> cx_power_coefficient = impurity.get_rate_coefficient("cx_power");

	// 	for(int k=0; k < Z; ++k){//N.b. iterating over all data indicies of the rate coefficient, hence the <
	// 		// m^-3 s^-1
	// 		double cx_recombination_coefficient_evaluated = cx_recombination_coefficient->call0D(k, Te_interp, Ne_interp);
	// 		double cx_recombination_rate = cx_recombination_coefficient_evaluated * Nn * Nzk[k+1];

	// 		// W m^-3
	// 		double cx_power_coefficient_evaluated = cx_power_coefficient->call0D(k, Te_interp, Ne_interp);
	// 		double cx_power_rate = cx_power_coefficient_evaluated * Nn * Nzk[k+1] / eV_to_J;

	// 		std::printf("cx: %e [m^-3 s^-1], cx_power: %e [eV m^-3 s^-1], per transition: %e [eV] \n", cx_recombination_rate, cx_power_rate, cx_power_rate/cx_recombination_rate);
	// 	}
	// }

}

<|endoftext|>


<commit_before><commit_msg>Plot SDD calibration history also for single sides<commit_after><|endoftext|>


<commit_before>#if !defined(__CINT__) || defined(__MAKECINT__)
#include <TFile.h>
#include <TH1F.h>
#include <TGraph.h>
#include <TGraphErrors.h>
#include <TStyle.h>
#include <TGrid.h>
#include <TCanvas.h>
#include <TSystem.h>
#include <TLatex.h>
#include <TLegend.h>
#include <TLegendEntry.h>
#include <TObjArray.h>
#include "AliCDBEntry.h"
#include "AliITSCalibrationSDD.h"
#endif

/*  $Id: PlotCalibSDDVsTime.C 41568 2010-06-03 09:08:39Z prino $    */

// Macro to plot the calibration parameters from the OCDB files
// created from PEDESTAL and PULSER runs vs. Time
// Origin: F. Prino (prino@to.infn.it)

void PlotCalibSDDVsTime(Int_t year=2011, Int_t firstRun=142600,
			Int_t lastRun=999999999,
			Int_t selectedMod=-1){

  gStyle->SetOptTitle(0);
  gStyle->SetOptStat(0);
  gStyle->SetPadLeftMargin(0.14);
  gStyle->SetTitleOffset(1.4,"Y");

  TGrid::Connect("alien:",0,0,"t");
  gSystem->Exec(Form("gbbox find \"/alice/data/%d/OCDB/ITS/Calib/CalibSDD\" \"Run*.root\" > runCalibAlien.txt",year));
  FILE* listruns=fopen("runCalibAlien.txt","r");

  TH1F* hbase=new TH1F("hbase","",60,0.5,120.5);
  TH1F* hnoise=new TH1F("hnoise","",100,0.,7.);
  TH1F* hgain=new TH1F("hgain","",100,0.,4.);
  TH1F* hchstatus=new TH1F("hchstatus","",2,-0.5,1.5);
  TH1F* hchstatus3=new TH1F("hchstatus3","",2,-0.5,1.5);
  TH1F* hchstatus4=new TH1F("hchstatus4","",2,-0.5,1.5);
  TGraphErrors* gbasevstim=new TGraphErrors(0);
  TGraphErrors* gnoisevstim=new TGraphErrors(0);
  TGraphErrors* ggainvstim=new TGraphErrors(0);
  TGraphErrors* gstatvstim=new TGraphErrors(0);
  TGraphErrors* gfracvstim=new TGraphErrors(0);
  TGraphErrors* gfrac3vstim=new TGraphErrors(0);
  TGraphErrors* gfrac4vstim=new TGraphErrors(0);
  gbasevstim->SetName("gbasevstim");
  gnoisevstim->SetName("gnoisevstim");
  ggainvstim->SetName("ggainvstim");
  gstatvstim->SetName("gstatvstim");
  gfracvstim->SetName("gfracvstim");
  gfrac3vstim->SetName("gfrac3vstim");
  gfrac4vstim->SetName("gfrac4vstim");
  gbasevstim->SetTitle("Baseline vs. run");
  gnoisevstim->SetTitle("Noise vs. run");
  ggainvstim->SetTitle("Gain vs. run");
  gstatvstim->SetTitle("Good Anodes vs. run");
  gfracvstim->SetTitle("Fraction of Good Anodes vs. run");
  gfrac3vstim->SetTitle("Fraction of Good Anodes vs. run");
  gfrac4vstim->SetTitle("Fraction of Good Anodes vs. run");

  Char_t filnam[200],filnamalien[200];
  Int_t iPoint=0;
  Int_t nrun,nrun2,nv,ns;

  while(!feof(listruns)){
    hbase->Reset();
    hnoise->Reset();
    hgain->Reset();
    hchstatus->Reset();
    hchstatus3->Reset();
    hchstatus4->Reset();
    fscanf(listruns,"%s\n",filnam);
    Char_t directory[100];
    sprintf(directory,"/alice/data/%d",year);
    if(!strstr(filnam,directory)) continue;
    sscanf(filnam,"/alice/data/%d/OCDB/ITS/Calib/CalibSDD/Run%d_%d_v%d_s%d.root",&year,&nrun,&nrun2,&nv,&ns);
    if(year==2009 && (nrun<85639 && nrun2> 85639)) continue; // protection for files with swapped ladders 4-5 of layer 3
    if(year==2009 && (nrun>100000 && nv< 184)) continue; // protection for files with swapped ladder 0-1 of layer 4
    if(year==2010 && (nrun>=114603 && nv< 98)) continue; // protection for files without treatment of masked hybrids
    if(year==2011 && (nrun>=145349 && nrun2> 148978)) continue; // protection for files affected by problem in second DA
    if(nrun<firstRun) continue;
    if(nrun>lastRun) continue;
    sprintf(filnamalien,"alien://%s",filnam);
    printf("Open file: %s\n",filnam);
    TFile *f= TFile::Open(filnamalien);
    AliCDBEntry *ent=(AliCDBEntry*)f->Get("AliCDBEntry");
    TObjArray *calSDD = (TObjArray *)ent->GetObject();
    printf("Run %d Entries in array=%d \n",nrun,calSDD->GetEntriesFast());

    AliITSCalibrationSDD *cal;
    for(Int_t iMod=0; iMod<260;iMod++){
      if(selectedMod>=240 && (iMod+240)!=selectedMod) continue;
      cal=(AliITSCalibrationSDD*)calSDD->At(iMod);
      if(cal==0) continue;
      for(Int_t iAn=0; iAn<512; iAn++){
	Int_t ic=cal->GetChip(iAn);
	Float_t base=cal->GetBaseline(iAn);
	Float_t noise=cal->GetNoiseAfterElectronics(iAn);
	Float_t gain=cal->GetChannelGain(iAn);
	if(cal->IsBadChannel(iAn)){
	  hchstatus->Fill(0);
	  if(iMod<84) hchstatus3->Fill(0);
	  else hchstatus4->Fill(0);
	}
	if(!cal->IsBadChannel(iAn) && !cal->IsChipBad(ic) && !cal->IsBad() ){
	  hbase->Fill(base);
	  hchstatus->Fill(1);
	  if(iMod<84) hchstatus3->Fill(1);
	  else hchstatus4->Fill(1);
	  hnoise->Fill(noise);
	  hgain->Fill(gain);
	}
      }
    }
    printf("Run %d <Base> = %f <Noise> =%f Entries = %d\n",nrun,hbase->GetMean(),hnoise->GetMean(),(Int_t)hbase->GetEntries());
    if(selectedMod==-1 && (Int_t)hbase->GetEntries()==0) continue;
    gbasevstim->SetPoint(iPoint,(Double_t)nrun,hbase->GetMean());
    gbasevstim->SetPointError(iPoint,0.,hbase->GetRMS());
    gnoisevstim->SetPoint(iPoint,(Double_t)nrun,hnoise->GetMean());
    gnoisevstim->SetPointError(iPoint,0.,hnoise->GetRMS());
    ggainvstim->SetPoint(iPoint,(Double_t)nrun,hgain->GetMean());
    ggainvstim->SetPointError(iPoint,0.,hgain->GetRMS());
    gstatvstim->SetPoint(iPoint,(Double_t)nrun,hchstatus->GetBinContent(2));
    Float_t normMod=260.;
    if(selectedMod!=-1) normMod=1.;
    gfracvstim->SetPoint(iPoint,(Double_t)nrun,hchstatus->GetBinContent(2)/normMod/512.);
    gfrac3vstim->SetPoint(iPoint,(Double_t)nrun,hchstatus3->GetBinContent(2)/84./512.);
    gfrac4vstim->SetPoint(iPoint,(Double_t)nrun,hchstatus4->GetBinContent(2)/176./512.);
    iPoint++;
    f->Close();
  }

  TFile *ofil=new TFile(Form("Calib%dVsTime.root",year),"recreate");
  gbasevstim->Write();
  gnoisevstim->Write();
  ggainvstim->Write();
  gstatvstim->Write();
  ofil->Close();

  TCanvas* cbase=new TCanvas("cbase","Baselines");
  gbasevstim->SetFillColor(kOrange-2);
  gbasevstim->SetMarkerStyle(20);
  gbasevstim->Draw("AP3");
  gbasevstim->Draw("PLXSAME");
  gbasevstim->SetMinimum(0.);
  gbasevstim->SetMaximum(70.);
  gbasevstim->GetXaxis()->SetTitle("Run number");
  gbasevstim->GetYaxis()->SetTitle("<Baseline> (ADC counts)");
  cbase->SaveAs(Form("BaseRun%d.gif",year));

  TCanvas* cnoise=new TCanvas("cnoise","Noise");
  gnoisevstim->SetFillColor(kOrange-2);
  gnoisevstim->SetMarkerStyle(20);
  gnoisevstim->Draw("AP3");
  gnoisevstim->Draw("PLXSAME");
  gnoisevstim->SetMinimum(0.);
  gnoisevstim->SetMaximum(4.);
  gnoisevstim->GetXaxis()->SetTitle("Run number");
  gnoisevstim->GetYaxis()->SetTitle("<Noise> (ADC counts)");
  cnoise->SaveAs(Form("NoiseRun%d.gif",year));

  TCanvas* cgain=new TCanvas("cgain","Gain");
  ggainvstim->SetFillColor(kOrange-2);
  ggainvstim->SetMarkerStyle(20);
  ggainvstim->Draw("AP3");
  ggainvstim->Draw("PLXSAME");
  ggainvstim->SetMinimum(0.);
  ggainvstim->SetMaximum(4.);
  ggainvstim->GetXaxis()->SetTitle("Run number");
  ggainvstim->GetYaxis()->SetTitle("<Gain> (ADC/DAC)");
  cgain->SaveAs(Form("GainRun%d.gif",year));

  TCanvas* cstatus=new TCanvas("cstatus","Good channels");
  gstatvstim->SetFillColor(kOrange-2);
  gstatvstim->SetMarkerStyle(20);
  gstatvstim->Draw("AP3");
  gstatvstim->Draw("PLXSAME");
  if(selectedMod==-1){
    gstatvstim->SetMinimum(100000.);
    gstatvstim->SetMaximum(133000.);
  }else{
    gstatvstim->SetMinimum(0.);
    gstatvstim->SetMaximum(512.);
  }
  gstatvstim->GetXaxis()->SetTitle("Run number");
  if(selectedMod==-1){
    gstatvstim->GetYaxis()->SetTitle("Number of good anodes in acquisition");
  }else{
    gstatvstim->GetYaxis()->SetTitle(Form("Number of good anodes in od %d",selectedMod));
  }
  cstatus->SaveAs(Form("GoodAnodesRun%d.gif",year));

  TCanvas* cfrac=new TCanvas("cfrac","Fraction of Good");
  gfracvstim->SetMarkerStyle(20);
  gfrac3vstim->SetMarkerStyle(22);
  gfrac3vstim->SetMarkerColor(2);
  gfrac3vstim->SetLineColor(2);
  gfrac4vstim->SetMarkerStyle(23);
  gfrac4vstim->SetMarkerColor(4);
  gfrac4vstim->SetLineColor(4);
  gfracvstim->Draw("APL");
  gfracvstim->SetMinimum(0.7);
  gfracvstim->SetMaximum(1.05);
  gfracvstim->GetXaxis()->SetTitle("Run number");
  if(selectedMod==-1){
    gfracvstim->GetYaxis()->SetTitle("Fraction of good anodes in acquisition");
    gfrac3vstim->Draw("PLSAME");
    gfrac4vstim->Draw("PLSAME");

    TLegend* leg=new TLegend(0.2,0.15,0.45,0.35);
    leg->SetFillColor(0);
    TLegendEntry* entr=leg->AddEntry(gfrac3vstim,"Layer 3","P");
    entr->SetTextColor(2);
    entr=leg->AddEntry(gfrac4vstim,"Layer 4","P");
    entr->SetTextColor(4);
    entr=leg->AddEntry(gfracvstim,"All","P");
    entr->SetTextColor(1);
    leg->Draw();
  }else{
    gfracvstim->GetYaxis()->SetTitle(Form("Fraction of good anodes in mod %d",selectedMod));
  }
  cfrac->SaveAs(Form("FractionGoodRun%d.gif",year));

}
<commit_msg>Minor fix in macro to plot SDD calibs<commit_after>#if !defined(__CINT__) || defined(__MAKECINT__)
#include <TFile.h>
#include <TH1F.h>
#include <TGraph.h>
#include <TGraphErrors.h>
#include <TStyle.h>
#include <TGrid.h>
#include <TCanvas.h>
#include <TSystem.h>
#include <TLatex.h>
#include <TLegend.h>
#include <TLegendEntry.h>
#include <TObjArray.h>
#include "AliCDBEntry.h"
#include "AliITSCalibrationSDD.h"
#endif

/*  $Id: PlotCalibSDDVsTime.C 41568 2010-06-03 09:08:39Z prino $    */

// Macro to plot the calibration parameters from the OCDB files
// created from PEDESTAL and PULSER runs vs. Time
// Origin: F. Prino (prino@to.infn.it)

void PlotCalibSDDVsTime(Int_t year=2011, Int_t firstRun=142600,
			Int_t lastRun=999999999,
			Int_t selectedMod=-1){

  gStyle->SetOptTitle(0);
  gStyle->SetOptStat(0);
  gStyle->SetPadLeftMargin(0.14);
  gStyle->SetTitleOffset(1.4,"Y");

  TGrid::Connect("alien:",0,0,"t");
  gSystem->Exec(Form("gbbox find \"/alice/data/%d/OCDB/ITS/Calib/CalibSDD\" \"Run*.root\" > runCalibAlien.txt",year));
  FILE* listruns=fopen("runCalibAlien.txt","r");

  TH1F* hbase=new TH1F("hbase","",60,0.5,120.5);
  TH1F* hnoise=new TH1F("hnoise","",100,0.,7.);
  TH1F* hgain=new TH1F("hgain","",100,0.,4.);
  TH1F* hchstatus=new TH1F("hchstatus","",2,-0.5,1.5);
  TH1F* hchstatus3=new TH1F("hchstatus3","",2,-0.5,1.5);
  TH1F* hchstatus4=new TH1F("hchstatus4","",2,-0.5,1.5);
  TGraphErrors* gbasevstim=new TGraphErrors(0);
  TGraphErrors* gnoisevstim=new TGraphErrors(0);
  TGraphErrors* ggainvstim=new TGraphErrors(0);
  TGraphErrors* gstatvstim=new TGraphErrors(0);
  TGraphErrors* gfracvstim=new TGraphErrors(0);
  TGraphErrors* gfrac3vstim=new TGraphErrors(0);
  TGraphErrors* gfrac4vstim=new TGraphErrors(0);
  gbasevstim->SetName("gbasevstim");
  gnoisevstim->SetName("gnoisevstim");
  ggainvstim->SetName("ggainvstim");
  gstatvstim->SetName("gstatvstim");
  gfracvstim->SetName("gfracvstim");
  gfrac3vstim->SetName("gfrac3vstim");
  gfrac4vstim->SetName("gfrac4vstim");
  gbasevstim->SetTitle("Baseline vs. run");
  gnoisevstim->SetTitle("Noise vs. run");
  ggainvstim->SetTitle("Gain vs. run");
  gstatvstim->SetTitle("Good Anodes vs. run");
  gfracvstim->SetTitle("Fraction of Good Anodes vs. run");
  gfrac3vstim->SetTitle("Fraction of Good Anodes vs. run");
  gfrac4vstim->SetTitle("Fraction of Good Anodes vs. run");

  Char_t filnam[200],filnamalien[200];
  Int_t iPoint=0;
  Int_t nrun,nrun2,nv,ns;

  while(!feof(listruns)){
    hbase->Reset();
    hnoise->Reset();
    hgain->Reset();
    hchstatus->Reset();
    hchstatus3->Reset();
    hchstatus4->Reset();
    fscanf(listruns,"%s\n",filnam);
    Char_t directory[100];
    sprintf(directory,"/alice/data/%d",year);
    if(!strstr(filnam,directory)) continue;
    sscanf(filnam,"/alice/data/%d/OCDB/ITS/Calib/CalibSDD/Run%d_%d_v%d_s%d.root",&year,&nrun,&nrun2,&nv,&ns);
    if(year==2009 && (nrun<85639 && nrun2> 85639)) continue; // protection for files with swapped ladders 4-5 of layer 3
    if(year==2009 && (nrun>100000 && nv< 184)) continue; // protection for files with swapped ladder 0-1 of layer 4
    if(year==2010 && (nrun>=114603 && nv< 98)) continue; // protection for files without treatment of masked hybrids
    if(year==2011 && (nrun>=145349 && nrun<=148978) && nrun2> 148978) continue; // protection for files affected by problem in second DA
    if(nrun<firstRun) continue;
    if(nrun>lastRun) continue;
    sprintf(filnamalien,"alien://%s",filnam);
    printf("Open file: %s\n",filnam);
    TFile *f= TFile::Open(filnamalien);
    AliCDBEntry *ent=(AliCDBEntry*)f->Get("AliCDBEntry");
    TObjArray *calSDD = (TObjArray *)ent->GetObject();
    printf("Run %d Entries in array=%d \n",nrun,calSDD->GetEntriesFast());

    AliITSCalibrationSDD *cal;
    for(Int_t iMod=0; iMod<260;iMod++){
      if(selectedMod>=240 && (iMod+240)!=selectedMod) continue;
      cal=(AliITSCalibrationSDD*)calSDD->At(iMod);
      if(cal==0) continue;
      for(Int_t iAn=0; iAn<512; iAn++){
	Int_t ic=cal->GetChip(iAn);
	Float_t base=cal->GetBaseline(iAn);
	Float_t noise=cal->GetNoiseAfterElectronics(iAn);
	Float_t gain=cal->GetChannelGain(iAn);
	if(cal->IsBadChannel(iAn)){
	  hchstatus->Fill(0);
	  if(iMod<84) hchstatus3->Fill(0);
	  else hchstatus4->Fill(0);
	}
	if(!cal->IsBadChannel(iAn) && !cal->IsChipBad(ic) && !cal->IsBad() ){
	  hbase->Fill(base);
	  hchstatus->Fill(1);
	  if(iMod<84) hchstatus3->Fill(1);
	  else hchstatus4->Fill(1);
	  hnoise->Fill(noise);
	  hgain->Fill(gain);
	}
      }
    }
    printf("Run %d <Base> = %f <Noise> =%f Entries = %d\n",nrun,hbase->GetMean(),hnoise->GetMean(),(Int_t)hbase->GetEntries());
    if(selectedMod==-1 && (Int_t)hbase->GetEntries()==0) continue;
    gbasevstim->SetPoint(iPoint,(Double_t)nrun,hbase->GetMean());
    gbasevstim->SetPointError(iPoint,0.,hbase->GetRMS());
    gnoisevstim->SetPoint(iPoint,(Double_t)nrun,hnoise->GetMean());
    gnoisevstim->SetPointError(iPoint,0.,hnoise->GetRMS());
    ggainvstim->SetPoint(iPoint,(Double_t)nrun,hgain->GetMean());
    ggainvstim->SetPointError(iPoint,0.,hgain->GetRMS());
    gstatvstim->SetPoint(iPoint,(Double_t)nrun,hchstatus->GetBinContent(2));
    Float_t normMod=260.;
    if(selectedMod!=-1) normMod=1.;
    gfracvstim->SetPoint(iPoint,(Double_t)nrun,hchstatus->GetBinContent(2)/normMod/512.);
    gfrac3vstim->SetPoint(iPoint,(Double_t)nrun,hchstatus3->GetBinContent(2)/84./512.);
    gfrac4vstim->SetPoint(iPoint,(Double_t)nrun,hchstatus4->GetBinContent(2)/176./512.);
    iPoint++;
    f->Close();
  }

  TFile *ofil=new TFile(Form("Calib%dVsTime.root",year),"recreate");
  gbasevstim->Write();
  gnoisevstim->Write();
  ggainvstim->Write();
  gstatvstim->Write();
  ofil->Close();

  TCanvas* cbase=new TCanvas("cbase","Baselines");
  gbasevstim->SetFillColor(kOrange-2);
  gbasevstim->SetMarkerStyle(20);
  gbasevstim->Draw("AP3");
  gbasevstim->Draw("PLXSAME");
  gbasevstim->SetMinimum(0.);
  gbasevstim->SetMaximum(70.);
  gbasevstim->GetXaxis()->SetTitle("Run number");
  gbasevstim->GetYaxis()->SetTitle("<Baseline> (ADC counts)");
  cbase->SaveAs(Form("BaseRun%d.gif",year));

  TCanvas* cnoise=new TCanvas("cnoise","Noise");
  gnoisevstim->SetFillColor(kOrange-2);
  gnoisevstim->SetMarkerStyle(20);
  gnoisevstim->Draw("AP3");
  gnoisevstim->Draw("PLXSAME");
  gnoisevstim->SetMinimum(0.);
  gnoisevstim->SetMaximum(4.);
  gnoisevstim->GetXaxis()->SetTitle("Run number");
  gnoisevstim->GetYaxis()->SetTitle("<Noise> (ADC counts)");
  cnoise->SaveAs(Form("NoiseRun%d.gif",year));

  TCanvas* cgain=new TCanvas("cgain","Gain");
  ggainvstim->SetFillColor(kOrange-2);
  ggainvstim->SetMarkerStyle(20);
  ggainvstim->Draw("AP3");
  ggainvstim->Draw("PLXSAME");
  ggainvstim->SetMinimum(0.);
  ggainvstim->SetMaximum(4.);
  ggainvstim->GetXaxis()->SetTitle("Run number");
  ggainvstim->GetYaxis()->SetTitle("<Gain> (ADC/DAC)");
  cgain->SaveAs(Form("GainRun%d.gif",year));

  TCanvas* cstatus=new TCanvas("cstatus","Good channels");
  gstatvstim->SetFillColor(kOrange-2);
  gstatvstim->SetMarkerStyle(20);
  gstatvstim->Draw("AP3");
  gstatvstim->Draw("PLXSAME");
  if(selectedMod==-1){
    gstatvstim->SetMinimum(100000.);
    gstatvstim->SetMaximum(133000.);
  }else{
    gstatvstim->SetMinimum(0.);
    gstatvstim->SetMaximum(512.);
  }
  gstatvstim->GetXaxis()->SetTitle("Run number");
  if(selectedMod==-1){
    gstatvstim->GetYaxis()->SetTitle("Number of good anodes in acquisition");
  }else{
    gstatvstim->GetYaxis()->SetTitle(Form("Number of good anodes in od %d",selectedMod));
  }
  cstatus->SaveAs(Form("GoodAnodesRun%d.gif",year));

  TCanvas* cfrac=new TCanvas("cfrac","Fraction of Good");
  gfracvstim->SetMarkerStyle(20);
  gfrac3vstim->SetMarkerStyle(22);
  gfrac3vstim->SetMarkerColor(2);
  gfrac3vstim->SetLineColor(2);
  gfrac4vstim->SetMarkerStyle(23);
  gfrac4vstim->SetMarkerColor(4);
  gfrac4vstim->SetLineColor(4);
  gfracvstim->Draw("APL");
  gfracvstim->SetMinimum(0.7);
  gfracvstim->SetMaximum(1.05);
  gfracvstim->GetXaxis()->SetTitle("Run number");
  if(selectedMod==-1){
    gfracvstim->GetYaxis()->SetTitle("Fraction of good anodes in acquisition");
    gfrac3vstim->Draw("PLSAME");
    gfrac4vstim->Draw("PLSAME");

    TLegend* leg=new TLegend(0.2,0.15,0.45,0.35);
    leg->SetFillColor(0);
    TLegendEntry* entr=leg->AddEntry(gfrac3vstim,"Layer 3","P");
    entr->SetTextColor(2);
    entr=leg->AddEntry(gfrac4vstim,"Layer 4","P");
    entr->SetTextColor(4);
    entr=leg->AddEntry(gfracvstim,"All","P");
    entr->SetTextColor(1);
    leg->Draw();
  }else{
    gfracvstim->GetYaxis()->SetTitle(Form("Fraction of good anodes in mod %d",selectedMod));
  }
  cfrac->SaveAs(Form("FractionGoodRun%d.gif",year));

}
<|endoftext|>


<commit_before>/*
 * Author: Jeff Thompson
 *
 * BSD license, See the LICENSE file for more information.
 */

#ifndef BINARYXMLSTRUCTUREDECODER_HPP
#define	BINARYXMLSTRUCTUREDECODER_HPP

#include <stdexcept>
#include "../c/encoding/BinaryXMLStructureDecoder.h"

namespace ndn {

/**
 * A BinaryXMLStructureDecoder wraps a C ndn_BinaryXMLStructureDecoder struct and related functions.
 */
class BinaryXMLStructureDecoder {
public:
  BinaryXMLStructureDecoder() {
    ndn_BinaryXMLStructureDecoder_init(&base_);
  }

  /**
   * Continue scanning input starting from getOffset() to find the element end.
   * If the end of the element which started at offset 0 is found, then return true and getOffset() is the length of
   *   the element.  Otherwise return false, which means you should read more into input and call again.
   * @param input the input buffer. You have to pass in input each time because the buffer could be reallocated.
   * @param inputLength the number of bytes in input.
   * @return true if found the element end, false if need to read more. (This is the same as returning gotElementEnd().)
   */
  bool findElementEnd(unsigned char *input, unsigned int inputLength) {
    char *error;
    if (error = ndn_BinaryXMLStructureDecoder_findElementEnd(&base_, input, inputLength))
      throw std::runtime_error(error);
    return gotElementEnd();
  }

  unsigned int getOffset() { return base_._offset; }
  bool gotElementEnd() { return base_.gotElementEnd != 0; }

private:
  struct ndn_BinaryXMLStructureDecoder base_;
};

}

#endif	/* BINARYXMLSTRUCTUREDECODER_HPP */

<commit_msg>Fix code style.<commit_after>/*
 * Author: Jeff Thompson
 *
 * BSD license, See the LICENSE file for more information.
 */

#ifndef BINARYXMLSTRUCTUREDECODER_HPP
#define	BINARYXMLSTRUCTUREDECODER_HPP

#include <stdexcept>
#include "../c/encoding/BinaryXMLStructureDecoder.h"

namespace ndn {

/**
 * A BinaryXMLStructureDecoder wraps a C ndn_BinaryXMLStructureDecoder struct and related functions.
 */
class BinaryXMLStructureDecoder {
public:
  BinaryXMLStructureDecoder()
  {
    ndn_BinaryXMLStructureDecoder_init(&base_);
  }

  /**
   * Continue scanning input starting from getOffset() to find the element end.
   * If the end of the element which started at offset 0 is found, then return true and getOffset() is the length of
   *   the element.  Otherwise return false, which means you should read more into input and call again.
   * @param input the input buffer. You have to pass in input each time because the buffer could be reallocated.
   * @param inputLength the number of bytes in input.
   * @return true if found the element end, false if need to read more. (This is the same as returning gotElementEnd().)
   */
  bool findElementEnd(unsigned char *input, unsigned int inputLength)
  {
    char *error;
    if (error = ndn_BinaryXMLStructureDecoder_findElementEnd(&base_, input, inputLength))
      throw std::runtime_error(error);
    return gotElementEnd();
  }

  unsigned int getOffset() { return base_._offset; }
  bool gotElementEnd() { return base_.gotElementEnd != 0; }

private:
  struct ndn_BinaryXMLStructureDecoder base_;
};

}

#endif	/* BINARYXMLSTRUCTUREDECODER_HPP */

<|endoftext|>


<commit_before>// Copyright (c) 2022 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include "errors.hh"
#include "scanner.hh"

namespace loxpp {

Scanner::Scanner(ErrorReporter& error_repoter, const str_t& source_bytes, const str_t& filename) noexcept
  : error_repoter_(error_repoter)
  , source_bytes_(source_bytes)
  , filename_(filename) {
}

std::vector<Token>& Scanner::scan_tokens() noexcept {
  while (!is_at_end()) {
    // TODO:

    start_pos_ = current_pos_;
    scan_token();
  }

  tokens_.push_back(Token::make_from_details(TokenType::TK_EOF, "", lineno_));
  return tokens_;
}

void Scanner::scan_token() noexcept {
  char c = advance();
  switch (c) {
  case '(': add_token(TokenType::TK_LPAREN); break;
  case ')': add_token(TokenType::TK_RPAREN); break;
  case '{': add_token(TokenType::TK_LBRACE); break;
  case '}': add_token(TokenType::TK_RBRACE); break;
  case ',': add_token(TokenType::TK_COMMA); break;
  case '.': add_token(TokenType::TK_DOT); break;
  case '-': add_token(TokenType::TK_MINUS); break;
  case '+': add_token(TokenType::TK_PLUS); break;
  case ';': add_token(TokenType::TK_SEMI); break;
  case '*': add_token(TokenType::TK_STAR); break;
  case '!': add_token(match('=') ? TokenType::TK_NE : TokenType::TK_NOT); break;
  case '=': add_token(match('=') ? TokenType::TK_EQEQ : TokenType::TK_EQ); break;
  case '<': add_token(match('=') ? TokenType::TK_LE : TokenType::TK_LT); break;
  case '>': add_token(match('=') ? TokenType::TK_GE : TokenType::TK_GT); break;
  case '/':
    if (match('/')) {
      // a comment goes until the end of the line.
      while (!is_at_end() && peek() != '\n')
        advance();
    }
    else {
      add_token(TokenType::TK_SLASH);
    }
    break;
  default:
    error_repoter_.error("", lineno_, "Unexpected character.");
    break;
  }
}

}
<commit_msg>:construction: chore(scanner): updated the implementation of scanner module<commit_after>// Copyright (c) 2022 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include "errors.hh"
#include "scanner.hh"

namespace loxpp {

Scanner::Scanner(ErrorReporter& error_repoter, const str_t& source_bytes, const str_t& filename) noexcept
  : error_repoter_(error_repoter)
  , source_bytes_(source_bytes)
  , filename_(filename) {
}

std::vector<Token>& Scanner::scan_tokens() noexcept {
  while (!is_at_end()) {
    // TODO:

    start_pos_ = current_pos_;
    scan_token();
  }

  tokens_.push_back(Token::make_from_details(TokenType::TK_EOF, "", lineno_));
  return tokens_;
}

void Scanner::scan_token() noexcept {
  char c = advance();
  switch (c) {
  case '(': add_token(TokenType::TK_LPAREN); break;
  case ')': add_token(TokenType::TK_RPAREN); break;
  case '{': add_token(TokenType::TK_LBRACE); break;
  case '}': add_token(TokenType::TK_RBRACE); break;
  case ',': add_token(TokenType::TK_COMMA); break;
  case '.': add_token(TokenType::TK_DOT); break;
  case '-': add_token(TokenType::TK_MINUS); break;
  case '+': add_token(TokenType::TK_PLUS); break;
  case ';': add_token(TokenType::TK_SEMI); break;
  case '*': add_token(TokenType::TK_STAR); break;
  case '!': add_token(match('=') ? TokenType::TK_NE : TokenType::TK_NOT); break;
  case '=': add_token(match('=') ? TokenType::TK_EQEQ : TokenType::TK_EQ); break;
  case '<': add_token(match('=') ? TokenType::TK_LE : TokenType::TK_LT); break;
  case '>': add_token(match('=') ? TokenType::TK_GE : TokenType::TK_GT); break;
  case '/':
    if (match('/')) {
      // a comment goes until the end of the line.
      while (!is_at_end() && peek() != '\n')
        advance();
    }
    else {
      add_token(TokenType::TK_SLASH);
    }
    break;
  case ' ':
  case '\r':
  case '\t':
    // Ignore whitespace
    break;
  case '\n': ++lineno_; break;
  case '"': string(); break;
  default:
    error_repoter_.error("", lineno_, "Unexpected character.");
    break;
  }
}

void Scanner::string() noexcept {
  while (!is_at_end() && peek() != '"') {
    if (peek() == '\n')
      ++lineno_;
    advance();
  }

  if (is_at_end()) {
    error_repoter_.error("", lineno_, "Unterminated string.");
    return;
  }

  // The closing ".
  advance();

  str_t literal = gen_literal(start_pos_ + 1, current_pos_ - 1);
  add_token(TokenType::TK_STRING, literal);
}

}
<|endoftext|>


<commit_before>/** \file    add_publication_year_to_serials.cc
 *  \brief   Add reasonable publication year to serials provided by an external list
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016-2018, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
    Background: Serials (i.e. "Schriftenreihen") do not in general provide a reasonable
    Sorting date, since the 008 is not properly filled. To circumvent this, we derive
    the sorting date from the the subordinate works and provide it as an (external) list.
    Based on this list, we insert the publication year to reasonable fields here
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "FileUtil.h"
#include "MARC.h"
#include "StringUtil.h"
#include "util.h"

namespace {

typedef std::map<std::string, std::string> SortList;

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " sort_year_list title_data_marc_input title_date_marc_output\n";
    std::exit(EXIT_FAILURE);
}

void SetupPublicationYearMap(File * const sort_year_list, SortList * const sort_year_map) {
    while (not sort_year_list->eof()) {
       std::string line(sort_year_list->getline());
       std::vector<std::string> ppns_and_sort_year;
       if (unlikely(StringUtil::SplitThenTrim(line, ":", " ",  &ppns_and_sort_year) != 2)) {
           LOG_WARNING("Invalid line: " + line);
           continue;
       }
       const std::string ppn(ppns_and_sort_year[0]);
       const std::string sort_year(ppns_and_sort_year[1]);
       sort_year_map->insert(std::make_pair(ppn, sort_year));
    }
}

static unsigned modified_count(0);

void ProcessRecord(MARC::Record * const record, const SortList &sort_year_map) {
    SortList::const_iterator iter(sort_year_map.find(record->getControlNumber()));
    if (iter == sort_year_map.cend())
       return;

    std::string sort_year(iter->second);

    // We insert in 190j
    // Case 1: If there is no 190 tag yet, insert subfield j and we are done
    if (not record->hasTag("190")) {
        record->insertField("190", { { 'j', sort_year } });
        ++modified_count;
        return;
    }

    // Case 2: There is a 190 tag
    MARC::Record::Range range(record->getTagRange("190"));
    for (auto &field : range) {
        MARC::Subfields subfields = field.getSubfields();
        if (subfields.hasSubfield('j'))
            LOG_ERROR("We already have a 190j subfield for PPN " + record->getControlNumber());

        // If there is no 190j subfield yet, we insert at the last field occurence
        if (field == *(range.end() - 1)) {
            subfields.appendSubfield('j', sort_year);
            ++modified_count;
        }
    }
}

void AddPublicationYearField(MARC::Reader * const marc_reader, MARC::Writer * const marc_writer,
                             const SortList &sort_year_map)
{
    unsigned record_count(0);
    while (MARC::Record record = marc_reader->read()) {
        ProcessRecord(&record, sort_year_map);
        marc_writer->write(record);
        ++record_count;
    }

    std::cout << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

} // unnamed namespace

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4)
        Usage();

    const std::string sort_year_list_filename(argv[1]);
    const std::string marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);

    if (unlikely(marc_input_filename == marc_output_filename))
        LOG_ERROR("Marc input filename equals marc output filename");

    if (unlikely(marc_input_filename == sort_year_list_filename || marc_output_filename == sort_year_list_filename))
        LOG_ERROR("Either marc input filename or marc output filename equals the sort list filename");

    try {
        std::unique_ptr<MARC::Reader> marc_reader(MARC::Reader::Factory(marc_input_filename, MARC::FileType::BINARY));
        std::unique_ptr<File> sort_year_list(FileUtil::OpenInputFileOrDie(sort_year_list_filename));
        std::unique_ptr<MARC::Writer> marc_writer(MARC::Writer::Factory(marc_output_filename, MARC::FileType::BINARY));
        SortList sort_year_map;
        SetupPublicationYearMap(sort_year_list.get(), &sort_year_map);
        AddPublicationYearField(marc_reader.get(), marc_writer.get(), sort_year_map);
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>add_publication_year_to_serials.cc: use range.back()<commit_after>/** \file    add_publication_year_to_serials.cc
 *  \brief   Add reasonable publication year to serials provided by an external list
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016-2018, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
    Background: Serials (i.e. "Schriftenreihen") do not in general provide a reasonable
    Sorting date, since the 008 is not properly filled. To circumvent this, we derive
    the sorting date from the the subordinate works and provide it as an (external) list.
    Based on this list, we insert the publication year to reasonable fields here
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "FileUtil.h"
#include "MARC.h"
#include "StringUtil.h"
#include "util.h"

namespace {

typedef std::map<std::string, std::string> SortList;

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " sort_year_list title_data_marc_input title_date_marc_output\n";
    std::exit(EXIT_FAILURE);
}

void SetupPublicationYearMap(File * const sort_year_list, SortList * const sort_year_map) {
    while (not sort_year_list->eof()) {
       std::string line(sort_year_list->getline());
       std::vector<std::string> ppns_and_sort_year;
       if (unlikely(StringUtil::SplitThenTrim(line, ":", " ",  &ppns_and_sort_year) != 2)) {
           LOG_WARNING("Invalid line: " + line);
           continue;
       }
       const std::string ppn(ppns_and_sort_year[0]);
       const std::string sort_year(ppns_and_sort_year[1]);
       sort_year_map->insert(std::make_pair(ppn, sort_year));
    }
}

static unsigned modified_count(0);

void ProcessRecord(MARC::Record * const record, const SortList &sort_year_map) {
    SortList::const_iterator iter(sort_year_map.find(record->getControlNumber()));
    if (iter == sort_year_map.cend())
       return;

    std::string sort_year(iter->second);

    // We insert in 190j
    // Case 1: If there is no 190 tag yet, insert subfield j and we are done
    if (not record->hasTag("190")) {
        record->insertField("190", { { 'j', sort_year } });
        ++modified_count;
        return;
    }

    // Case 2: There is a 190 tag
    MARC::Record::Range range(record->getTagRange("190"));
    for (auto &field : range) {
        MARC::Subfields subfields = field.getSubfields();
        if (subfields.hasSubfield('j'))
            LOG_ERROR("We already have a 190j subfield for PPN " + record->getControlNumber());

        // If there is no 190j subfield yet, we insert at the last field occurence
        if (field == range.back()) {
            subfields.appendSubfield('j', sort_year);
            ++modified_count;
        }
    }
}

void AddPublicationYearField(MARC::Reader * const marc_reader, MARC::Writer * const marc_writer,
                             const SortList &sort_year_map)
{
    unsigned record_count(0);
    while (MARC::Record record = marc_reader->read()) {
        ProcessRecord(&record, sort_year_map);
        marc_writer->write(record);
        ++record_count;
    }

    std::cout << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

} // unnamed namespace

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4)
        Usage();

    const std::string sort_year_list_filename(argv[1]);
    const std::string marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);

    if (unlikely(marc_input_filename == marc_output_filename))
        LOG_ERROR("Marc input filename equals marc output filename");

    if (unlikely(marc_input_filename == sort_year_list_filename || marc_output_filename == sort_year_list_filename))
        LOG_ERROR("Either marc input filename or marc output filename equals the sort list filename");

    try {
        std::unique_ptr<MARC::Reader> marc_reader(MARC::Reader::Factory(marc_input_filename, MARC::FileType::BINARY));
        std::unique_ptr<File> sort_year_list(FileUtil::OpenInputFileOrDie(sort_year_list_filename));
        std::unique_ptr<MARC::Writer> marc_writer(MARC::Writer::Factory(marc_output_filename, MARC::FileType::BINARY));
        SortList sort_year_map;
        SetupPublicationYearMap(sort_year_list.get(), &sort_year_map);
        AddPublicationYearField(marc_reader.get(), marc_writer.get(), sort_year_map);
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>/** \brief Tool for generating reasonable input for the FulltextImporter if only a PDF fulltext is available
 *  \author Johannes Riedl
 *
 *  \copyright 2019 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include "FileUtil.h"
#include "FullTextImport.h"
#include "HtmlUtil.h"
#include "PdfUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "util.h"

// Try to derive relevant information to guess the PPN
// Strategy 1: Try to find an ISBN string
// Strategy 2: Extract pages at the beginning and try to identify information at
//             the bottom of the first page and try to guess author and title

namespace {

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " [--min-log-level=min_verbosity] pdf_input full_text_output\n"
                           << ::progname << " [--min-log-level=min_verbosity] --output_dir output_dir pdf_input1 pdf_input2 ...\n\n";
    std::exit(EXIT_FAILURE);
}

std::string GuessLastParagraph(const std::string &first_page_text) {
    const std::string first_page_text_trimmed(StringUtil::Trim(first_page_text, '\n'));
    const std::size_t last_paragraph_start(first_page_text_trimmed.rfind("\n\n"));
    std::string last_paragraph(last_paragraph_start != std::string::npos ?
                               first_page_text_trimmed.substr(last_paragraph_start) : "");
    StringUtil::Map(&last_paragraph, '\n', ' ');
    return TextUtil::NormaliseDashes(&last_paragraph);
}

bool GuessISSN(const std::string &first_page_text, std::string * const issn) {
    const std::string last_paragraph(GuessLastParagraph(first_page_text));
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactoryOrDie(".*ISSN\\s*([\\d\\-X]+).*"));
    if (matcher->matched(last_paragraph)) {
        *issn = (*matcher)[1];
        return true;
    }
    return false;
}

bool GuessDOI(const std::string &first_page_text, std::string * const doi) {
     const std::string last_paragraph(GuessLastParagraph(first_page_text));
     static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactoryOrDie(".*DOI[\\s:]*([\\d/.X]+).*", RegexMatcher::CASE_INSENSITIVE));
     if (matcher->matched(last_paragraph)) {
         *doi = (*matcher)[1];
         return true;
     }
     return false;
}

bool GuessISBN(const std::string &extracted_text, std::string * const isbn) {
     static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactoryOrDie(".*(?<!e-)ISBN\\s*([\\d\\-X]+).*", RegexMatcher::CASE_INSENSITIVE));
     if (matcher->matched(extracted_text)) {
         *isbn = (*matcher)[1];
         return true;
     }
     return false;
}

void GuessAuthorAndTitle(const std::string &pdf_document, FullTextImport::FullTextData * const fulltext_data) {
    std::string pdfinfo_output;
    PdfUtil::ExtractPDFInfo(pdf_document, &pdfinfo_output);
    static RegexMatcher * const authors_matcher(RegexMatcher::RegexMatcherFactoryOrDie("Author:\\s*(.*)", RegexMatcher::CASE_INSENSITIVE));
    std::vector<std::string> authors;
    if (authors_matcher->matched(pdfinfo_output)) {
        StringUtil::Split((*authors_matcher)[1], std::set<char>{ ';', '|' }, &authors);
        for (auto &author : authors)
            author = HtmlUtil::ReplaceEntities(author);
        std::copy(authors.cbegin(), authors.cend(), std::inserter(fulltext_data->authors_, fulltext_data->authors_.end()));
    }
    static RegexMatcher * const title_matcher(RegexMatcher::RegexMatcherFactoryOrDie("^Title:?\\s*(.*)", RegexMatcher::CASE_INSENSITIVE));
    if (title_matcher->matched(pdfinfo_output)) {
        std::string title_candidate((*title_matcher)[1]);
        // Try to detect invalid encoding
        if (not TextUtil::IsValidUTF8(title_candidate))
            LOG_WARNING("Apparently incorrect encoding for " + title_candidate);
        // Some cleanup
        title_candidate = StringUtil::ReplaceString("<ger>", "", title_candidate);
        title_candidate = StringUtil::ReplaceString("</ger>", "", title_candidate);
        title_candidate = HtmlUtil::ReplaceEntities(title_candidate);
        fulltext_data->title_ = title_candidate;
    }
}

void ConvertFulltextMetadataFromAssumedLatin1OriginalEncoding(FullTextImport::FullTextData * const fulltext_data) {
    std::string error_msg;
    static auto UTF8ToLatin1_converter(TextUtil::EncodingConverter::Factory("utf-8", "ISO-8859-1", &error_msg));
    UTF8ToLatin1_converter->convert(fulltext_data->title_, &(fulltext_data->title_));
}

bool GuessPDFMetadata(const std::string &pdf_document, FullTextImport::FullTextData * const fulltext_data) {
    ControlNumberGuesser control_number_guesser;
    // Try to find an ISBN in the first pages
    std::string first_pages_text;
    PdfUtil::ExtractText(pdf_document, &first_pages_text, "1", "10" );
    std::string isbn;
    GuessISBN(TextUtil::NormaliseDashes(&first_pages_text), &isbn);
    if (not isbn.empty()) {
        LOG_DEBUG("Extracted ISBN: " + isbn);
        std::set<std::string> control_numbers;
        control_number_guesser.lookupISBN(isbn, &control_numbers);
        if (control_numbers.size() != 1) {
            LOG_WARNING("We got more than one control number for ISBN \"" + isbn + "\"  - falling back to title and author");
            GuessAuthorAndTitle(pdf_document, fulltext_data);
            fulltext_data->isbn_ = isbn;
            if (unlikely(not FullTextImport::CorrelateFullTextData(control_number_guesser, *(fulltext_data), &control_numbers))) {
                LOG_WARNING("Could not correlate full text data for ISBN \"" + isbn  + "\"");
                return false;
            }
            if (control_numbers.size() != 1)
                LOG_WARNING("Unable to determine unique control number for ISBN \"" + isbn + "\": " + StringUtil::Join(control_numbers, ", "));
        }
        const std::string control_number(*(control_numbers.begin()));
        LOG_DEBUG("Determined control number \"" + control_number + "\" for ISBN \"" + isbn + "\"\n");
        return true;
    }

    // Guess control number by DOI, author, title and and possibly ISSN
    std::string first_page_text;
    PdfUtil::ExtractText(pdf_document, &first_page_text, "1", "1"); // Get only first page
    std::string control_number;
    if (GuessDOI(first_page_text, &(fulltext_data->doi_))
        and FullTextImport::CorrelateFullTextData(control_number_guesser, *(fulltext_data), &control_number))
        return true;
    GuessISSN(first_page_text, &(fulltext_data->issn_));
    GuessAuthorAndTitle(pdf_document, fulltext_data);
    if (not FullTextImport::CorrelateFullTextData(control_number_guesser, *(fulltext_data), &control_number))
        // We frequently have the case that author and title extracted we encoded in Latin-1 in some time in the past such that our search fails
        // so force normalisation and make another attempt.
        ConvertFulltextMetadataFromAssumedLatin1OriginalEncoding(fulltext_data);
    return FullTextImport::CorrelateFullTextData(control_number_guesser, *(fulltext_data), &control_number);
}

void CreateFulltextImportFile(const std::string &fulltext_pdf, const std::string &fulltext_txt) {
    std::cout << "Processing \"" << fulltext_pdf << "\"\n";
    FullTextImport::FullTextData fulltext_data;
    std::string pdf_document;
    if (not FileUtil::ReadString(fulltext_pdf, &pdf_document))
        LOG_ERROR("Could not read \"" + fulltext_pdf + "\"");
    if (PdfUtil::PdfDocContainsNoText(pdf_document))
        LOG_ERROR("Apparently no text in \"" + fulltext_pdf + "\"");
    if (unlikely(not GuessPDFMetadata(pdf_document, &fulltext_data)))
        LOG_ERROR("Unable to determine metadata for \"" +  fulltext_pdf + "\"");
    if (unlikely(not PdfUtil::ExtractText(pdf_document, &(fulltext_data.full_text_))))
        LOG_ERROR("Unable to extract fulltext from \"" + fulltext_pdf + "\"");
    auto plain_text_output(FileUtil::OpenOutputFileOrDie(fulltext_txt));
    FullTextImport::WriteExtractedTextToDisk(fulltext_data.full_text_, fulltext_data.title_, fulltext_data.authors_, fulltext_data.doi_,
                                             fulltext_data.year_, fulltext_data.issn_, fulltext_data.isbn_, fulltext_data.text_type_, plain_text_output.get());
}

std::string DeriveOutputFilename(const std::string &pdf_filename) {
    return (StringUtil::ASCIIToLower(FileUtil::GetExtension(pdf_filename)) == "pdf") ?
        FileUtil::GetFilenameWithoutExtensionOrDie(pdf_filename) + ".txt" : pdf_filename + ".txt";
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc < 3)
        Usage();

    bool use_output_dir(false);
    std::string output_dir(".");
    if (argc > 2 and StringUtil::StartsWith(argv[1], "--output-dir=")) {
        use_output_dir = true;
        output_dir = argv[1] + __builtin_strlen("--output-dir=");
        --argc;
        ++argv;
    }

    if (argc < 2)
        Usage();

    if (not use_output_dir and argc < 3)
        Usage();

    if (not use_output_dir) {
        const std::string fulltext_pdf(argv[1]);
        CreateFulltextImportFile(fulltext_pdf, argv[2]);
        return EXIT_SUCCESS;
    }

    for (int arg_no(1); arg_no < argc; ++arg_no)
        CreateFulltextImportFile(argv[arg_no], output_dir + '/' + DeriveOutputFilename(argv[arg_no]));
    return EXIT_SUCCESS;
}
<commit_msg>Fix typo<commit_after>/** \brief Tool for generating reasonable input for the FulltextImporter if only a PDF fulltext is available
 *  \author Johannes Riedl
 *
 *  \copyright 2019 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include "FileUtil.h"
#include "FullTextImport.h"
#include "HtmlUtil.h"
#include "PdfUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "util.h"

// Try to derive relevant information to guess the PPN
// Strategy 1: Try to find an ISBN string
// Strategy 2: Extract pages at the beginning and try to identify information at
//             the bottom of the first page and try to guess author and title

namespace {

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " [--min-log-level=min_verbosity] pdf_input full_text_output\n"
                           << ::progname << " [--min-log-level=min_verbosity] --output-dir output_dir pdf_input1 pdf_input2 ...\n\n";
    std::exit(EXIT_FAILURE);
}

std::string GuessLastParagraph(const std::string &first_page_text) {
    const std::string first_page_text_trimmed(StringUtil::Trim(first_page_text, '\n'));
    const std::size_t last_paragraph_start(first_page_text_trimmed.rfind("\n\n"));
    std::string last_paragraph(last_paragraph_start != std::string::npos ?
                               first_page_text_trimmed.substr(last_paragraph_start) : "");
    StringUtil::Map(&last_paragraph, '\n', ' ');
    return TextUtil::NormaliseDashes(&last_paragraph);
}

bool GuessISSN(const std::string &first_page_text, std::string * const issn) {
    const std::string last_paragraph(GuessLastParagraph(first_page_text));
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactoryOrDie(".*ISSN\\s*([\\d\\-X]+).*"));
    if (matcher->matched(last_paragraph)) {
        *issn = (*matcher)[1];
        return true;
    }
    return false;
}

bool GuessDOI(const std::string &first_page_text, std::string * const doi) {
     const std::string last_paragraph(GuessLastParagraph(first_page_text));
     static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactoryOrDie(".*DOI[\\s:]*([\\d/.X]+).*", RegexMatcher::CASE_INSENSITIVE));
     if (matcher->matched(last_paragraph)) {
         *doi = (*matcher)[1];
         return true;
     }
     return false;
}

bool GuessISBN(const std::string &extracted_text, std::string * const isbn) {
     static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactoryOrDie(".*(?<!e-)ISBN\\s*([\\d\\-X]+).*", RegexMatcher::CASE_INSENSITIVE));
     if (matcher->matched(extracted_text)) {
         *isbn = (*matcher)[1];
         return true;
     }
     return false;
}

void GuessAuthorAndTitle(const std::string &pdf_document, FullTextImport::FullTextData * const fulltext_data) {
    std::string pdfinfo_output;
    PdfUtil::ExtractPDFInfo(pdf_document, &pdfinfo_output);
    static RegexMatcher * const authors_matcher(RegexMatcher::RegexMatcherFactoryOrDie("Author:\\s*(.*)", RegexMatcher::CASE_INSENSITIVE));
    std::vector<std::string> authors;
    if (authors_matcher->matched(pdfinfo_output)) {
        StringUtil::Split((*authors_matcher)[1], std::set<char>{ ';', '|' }, &authors);
        for (auto &author : authors)
            author = HtmlUtil::ReplaceEntities(author);
        std::copy(authors.cbegin(), authors.cend(), std::inserter(fulltext_data->authors_, fulltext_data->authors_.end()));
    }
    static RegexMatcher * const title_matcher(RegexMatcher::RegexMatcherFactoryOrDie("^Title:?\\s*(.*)", RegexMatcher::CASE_INSENSITIVE));
    if (title_matcher->matched(pdfinfo_output)) {
        std::string title_candidate((*title_matcher)[1]);
        // Try to detect invalid encoding
        if (not TextUtil::IsValidUTF8(title_candidate))
            LOG_WARNING("Apparently incorrect encoding for " + title_candidate);
        // Some cleanup
        title_candidate = StringUtil::ReplaceString("<ger>", "", title_candidate);
        title_candidate = StringUtil::ReplaceString("</ger>", "", title_candidate);
        title_candidate = HtmlUtil::ReplaceEntities(title_candidate);
        fulltext_data->title_ = title_candidate;
    }
}

void ConvertFulltextMetadataFromAssumedLatin1OriginalEncoding(FullTextImport::FullTextData * const fulltext_data) {
    std::string error_msg;
    static auto UTF8ToLatin1_converter(TextUtil::EncodingConverter::Factory("utf-8", "ISO-8859-1", &error_msg));
    UTF8ToLatin1_converter->convert(fulltext_data->title_, &(fulltext_data->title_));
}

bool GuessPDFMetadata(const std::string &pdf_document, FullTextImport::FullTextData * const fulltext_data) {
    ControlNumberGuesser control_number_guesser;
    // Try to find an ISBN in the first pages
    std::string first_pages_text;
    PdfUtil::ExtractText(pdf_document, &first_pages_text, "1", "10" );
    std::string isbn;
    GuessISBN(TextUtil::NormaliseDashes(&first_pages_text), &isbn);
    if (not isbn.empty()) {
        LOG_DEBUG("Extracted ISBN: " + isbn);
        std::set<std::string> control_numbers;
        control_number_guesser.lookupISBN(isbn, &control_numbers);
        if (control_numbers.size() != 1) {
            LOG_WARNING("We got more than one control number for ISBN \"" + isbn + "\"  - falling back to title and author");
            GuessAuthorAndTitle(pdf_document, fulltext_data);
            fulltext_data->isbn_ = isbn;
            if (unlikely(not FullTextImport::CorrelateFullTextData(control_number_guesser, *(fulltext_data), &control_numbers))) {
                LOG_WARNING("Could not correlate full text data for ISBN \"" + isbn  + "\"");
                return false;
            }
            if (control_numbers.size() != 1)
                LOG_WARNING("Unable to determine unique control number for ISBN \"" + isbn + "\": " + StringUtil::Join(control_numbers, ", "));
        }
        const std::string control_number(*(control_numbers.begin()));
        LOG_DEBUG("Determined control number \"" + control_number + "\" for ISBN \"" + isbn + "\"\n");
        return true;
    }

    // Guess control number by DOI, author, title and and possibly ISSN
    std::string first_page_text;
    PdfUtil::ExtractText(pdf_document, &first_page_text, "1", "1"); // Get only first page
    std::string control_number;
    if (GuessDOI(first_page_text, &(fulltext_data->doi_))
        and FullTextImport::CorrelateFullTextData(control_number_guesser, *(fulltext_data), &control_number))
        return true;
    GuessISSN(first_page_text, &(fulltext_data->issn_));
    GuessAuthorAndTitle(pdf_document, fulltext_data);
    if (not FullTextImport::CorrelateFullTextData(control_number_guesser, *(fulltext_data), &control_number))
        // We frequently have the case that author and title extracted we encoded in Latin-1 in some time in the past such that our search fails
        // so force normalisation and make another attempt.
        ConvertFulltextMetadataFromAssumedLatin1OriginalEncoding(fulltext_data);
    return FullTextImport::CorrelateFullTextData(control_number_guesser, *(fulltext_data), &control_number);
}

void CreateFulltextImportFile(const std::string &fulltext_pdf, const std::string &fulltext_txt) {
    std::cout << "Processing \"" << fulltext_pdf << "\"\n";
    FullTextImport::FullTextData fulltext_data;
    std::string pdf_document;
    if (not FileUtil::ReadString(fulltext_pdf, &pdf_document))
        LOG_ERROR("Could not read \"" + fulltext_pdf + "\"");
    if (PdfUtil::PdfDocContainsNoText(pdf_document))
        LOG_ERROR("Apparently no text in \"" + fulltext_pdf + "\"");
    if (unlikely(not GuessPDFMetadata(pdf_document, &fulltext_data)))
        LOG_ERROR("Unable to determine metadata for \"" +  fulltext_pdf + "\"");
    if (unlikely(not PdfUtil::ExtractText(pdf_document, &(fulltext_data.full_text_))))
        LOG_ERROR("Unable to extract fulltext from \"" + fulltext_pdf + "\"");
    auto plain_text_output(FileUtil::OpenOutputFileOrDie(fulltext_txt));
    FullTextImport::WriteExtractedTextToDisk(fulltext_data.full_text_, fulltext_data.title_, fulltext_data.authors_, fulltext_data.doi_,
                                             fulltext_data.year_, fulltext_data.issn_, fulltext_data.isbn_, fulltext_data.text_type_, plain_text_output.get());
}

std::string DeriveOutputFilename(const std::string &pdf_filename) {
    return (StringUtil::ASCIIToLower(FileUtil::GetExtension(pdf_filename)) == "pdf") ?
        FileUtil::GetFilenameWithoutExtensionOrDie(pdf_filename) + ".txt" : pdf_filename + ".txt";
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc < 3)
        Usage();

    bool use_output_dir(false);
    std::string output_dir(".");
    if (argc > 2 and StringUtil::StartsWith(argv[1], "--output-dir=")) {
        use_output_dir = true;
        output_dir = argv[1] + __builtin_strlen("--output-dir=");
        --argc;
        ++argv;
    }

    if (argc < 2)
        Usage();

    if (not use_output_dir and argc < 3)
        Usage();

    if (not use_output_dir) {
        const std::string fulltext_pdf(argv[1]);
        CreateFulltextImportFile(fulltext_pdf, argv[2]);
        return EXIT_SUCCESS;
    }

    for (int arg_no(1); arg_no < argc; ++arg_no)
        CreateFulltextImportFile(argv[arg_no], output_dir + '/' + DeriveOutputFilename(argv[arg_no]));
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    MeshCellVisitor.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

//  Software Guide : BeginLatex
//
//  Cells are stored in the \code{itk::Mesh} as pointers to a generic cell.
//  This implies that only the virtual methods defined on this base cell class
//  can be invoked. In order to use methods that are specific of each cell type
//  it is necessary to down-cast the pointer to the actual type of the cell.
//  This can be done safely by taking advantage of the C++ RTTI mechanism
//  \footnote{RTTI stands for Run Time Type Information}.
//
//  Let's start by assuming a mesh defined with one tetrahedron and all its
//  boundary faces. That is, four triangles, six edges and four vertices.
//
//  \index{RTTI}
//
//  Software Guide : EndLatex

#include "itkMesh.h"
#include "itkVertexCell.h"
#include "itkLineCell.h"
#include "itkTriangleCell.h"
#include "itkTetrahedronCell.h"

int main()
{

  typedef float                             PixelType;
  typedef itk::Mesh< PixelType, 3 >         MeshType;

  typedef MeshType::CellType                CellType;

  typedef itk::VertexCell< CellType >       VertexType;
  typedef itk::LineCell< CellType >         LineType;
  typedef itk::TriangleCell< CellType >     TriangleType;
  typedef itk::TetrahedronCell< CellType >  TetrahedronType;

  MeshType::Pointer  mesh = MeshType::New();

  //
  // Creating the points and inserting them in the mesh
  //
  MeshType::PointType   point0;
  MeshType::PointType   point1;
  MeshType::PointType   point2;
  MeshType::PointType   point3;

  point0[0] = -1; point0[1] = -1; point0[2] = -1;
  point1[0] =  1; point1[1] =  1; point1[2] = -1;
  point2[0] =  1; point2[1] = -1; point2[2] =  1;
  point3[0] = -1; point3[1] =  1; point3[2] =  1;

  mesh->SetPoint( 0, point0 );
  mesh->SetPoint( 1, point1 );
  mesh->SetPoint( 2, point2 );
  mesh->SetPoint( 3, point3 );

  //
  // Creating and associating the Tetrahedron
  //
  CellType::CellAutoPointer cellpointer;

  cellpointer.TakeOwnership( new TetrahedronType );
  cellpointer->SetPointId( 0, 0 );
  cellpointer->SetPointId( 1, 1 );
  cellpointer->SetPointId( 2, 2 );
  cellpointer->SetPointId( 3, 3 );
  mesh->SetCell( 0, cellpointer );

  //
  // Creating and associating the Triangles
  //
  cellpointer.TakeOwnership( new TriangleType );
  cellpointer->SetPointId( 0, 0 );
  cellpointer->SetPointId( 1, 1 );
  cellpointer->SetPointId( 2, 2 );
  mesh->SetCell( 1, cellpointer );

  cellpointer.TakeOwnership( new TriangleType );
  cellpointer->SetPointId( 0, 0 );
  cellpointer->SetPointId( 1, 2 );
  cellpointer->SetPointId( 2, 3 );
  mesh->SetCell( 2, cellpointer );

  cellpointer.TakeOwnership( new TriangleType );
  cellpointer->SetPointId( 0, 0 );
  cellpointer->SetPointId( 1, 3 );
  cellpointer->SetPointId( 2, 1 );
  mesh->SetCell( 3, cellpointer );

  cellpointer.TakeOwnership( new TriangleType );
  cellpointer->SetPointId( 0, 3 );
  cellpointer->SetPointId( 1, 2 );
  cellpointer->SetPointId( 2, 1 );
  mesh->SetCell( 4, cellpointer );

  //
  // Creating and associating the Edges
  //
  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 0 );
  cellpointer->SetPointId( 1, 1 );
  mesh->SetCell( 5, cellpointer );

  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 1 );
  cellpointer->SetPointId( 1, 2 );
  mesh->SetCell( 6, cellpointer );

  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 2 );
  cellpointer->SetPointId( 1, 0 );
  mesh->SetCell( 7, cellpointer );

  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 1 );
  cellpointer->SetPointId( 1, 3 );
  mesh->SetCell( 8, cellpointer );

  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 3 );
  cellpointer->SetPointId( 1, 2 );
  mesh->SetCell( 9, cellpointer );

  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 3 );
  cellpointer->SetPointId( 1, 0 );
  mesh->SetCell( 10, cellpointer );

  //
  // Creating and associating the Vertices
  //
  cellpointer.TakeOwnership( new VertexType );
  cellpointer->SetPointId( 0, 0 );
  mesh->SetCell( 11, cellpointer );

  cellpointer.TakeOwnership( new VertexType );
  cellpointer->SetPointId( 0, 1 );
  mesh->SetCell( 12, cellpointer );

  cellpointer.TakeOwnership( new VertexType );
  cellpointer->SetPointId( 0, 2 );
  mesh->SetCell( 13, cellpointer );

  cellpointer.TakeOwnership( new VertexType );
  cellpointer->SetPointId( 0, 3 );
  mesh->SetCell( 14, cellpointer );

  std::cout << "# Points= " << mesh->GetNumberOfPoints() << std::endl;
  std::cout << "# Cell  = " << mesh->GetNumberOfCells() << std::endl;

  //  Software Guide : BeginLatex
  //
  //  The cells can be visited using CellsContainer iterators . The iterator
  //  \code{Value()} corresponds to a raw pointer to the \code{CellType} base
  //  class.
  //
  // \index{itk::Mesh!CellsContainer}
  // \index{itk::Mesh!CellsIterators}
  // \index{itk::Mesh!GetCells()}
  // \index{CellsContainer!Begin()}
  // \index{CellsContainer!End()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef MeshType::CellsContainer::ConstIterator  CellIterator;

  CellIterator cellIterator = mesh->GetCells()->Begin();
  CellIterator cellEnd      = mesh->GetCells()->End();

  while( cellIterator != cellEnd )
    {
    CellType * cell = cellIterator.Value();
    std::cout << cell->GetNumberOfPoints() << std::endl;
    ++cellIterator;
    }

  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Two mechanisms can be used to safely down-cast the pointer to the actual
  //  cell type. The first is a built-in mechanism in ITK that allows the user
  //  to query the type of the Cell. Codes for the cell types have been defined
  //  with an \code{enum} type on the \code{itkCellInterface.h} header file.
  //  These codes are : VERTEX\_CELL, LINE\_CELL, TRIANGLE\_CELL,
  //  QUADRILATERAL\_CELL, POLYGON\_CELL, TETRAHEDRON\_CELL, HEXAHEDRON\_CELL,
  //  QUADRATIC\_EDGE\_CELL, QUADRATIC\_TRIANGLE\_CELL. The Cell type is returned
  //  by the method \code{GetType()}. It is then possible to test the type of
  //  the cell before down-casting its pointer to the actual type. For example,
  //  the following code visits all the cells in the mesh and test which ones
  //  are actually of type LINE\_CELL. Only those cells are down-casted to
  //  LineType cells and a method specific for the LineType are invoked.
  //
  //  Software Guide : EndLatex

  std::cout << "Visiting the Line cells : " << std::endl;

  // Software Guide : BeginCodeSnippet
  cellIterator = mesh->GetCells()->Begin();
  cellEnd      = mesh->GetCells()->End();

  while( cellIterator != cellEnd )
    {
    CellType * cell = cellIterator.Value();
    if( cell->GetType() == CellType::LINE_CELL )
      {
      LineType * line = static_cast<LineType *>( cell );
      std::cout << "dimension = " << line->GetDimension()      << std::endl;
      std::cout << "# points  = " << line->GetNumberOfPoints() << std::endl;
      }
    ++cellIterator;
    }
  // Software Guide : EndCodeSnippet

  return 0;

}

<commit_msg>ENH: CellInterfaceVisitor introduced. The text needs to be reworked now.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    MeshCellVisitor.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

//  Software Guide : BeginLatex
//
//  Cells are stored in the \code{itk::Mesh} as pointers to a generic cell.
//  This implies that only the virtual methods defined on this base cell class
//  can be invoked. In order to use methods that are specific of each cell type
//  it is necessary to down-cast the pointer to the actual type of the cell.
//  This can be done safely by taking advantage of the C++ RTTI mechanism
//  \footnote{RTTI stands for Run Time Type Information}.
//
//  Let's start by assuming a mesh defined with one tetrahedron and all its
//  boundary faces. That is, four triangles, six edges and four vertices.
//
//  \index{RTTI}
//
//  Software Guide : EndLatex

#include "itkMesh.h"
#include "itkVertexCell.h"
#include "itkLineCell.h"
#include "itkTriangleCell.h"
#include "itkTetrahedronCell.h"

// Software Guide : BeginCodeSnippet
#include "itkCellInterfaceVisitor.h"
// Software Guide : EndCodeSnippet

  typedef float                             PixelType;
  typedef itk::Mesh< PixelType, 3 >         MeshType;

  typedef MeshType::CellType                CellType;

  typedef itk::VertexCell< CellType >       VertexType;
  typedef itk::LineCell< CellType >         LineType;
  typedef itk::TriangleCell< CellType >     TriangleType;
  typedef itk::TetrahedronCell< CellType >  TetrahedronType;

  // Software Guide : BeginCodeSnippet
  class CustomTriangleVisitor
    {
    public:
      typedef itk::TriangleCell<CellType>      TriangleType;

    public:
    void Visit(unsigned long cellId, TriangleType * t )
      {
      CellType::PointIdIterator pit = t->PointIdsBegin();
      CellType::PointIdIterator end = t->PointIdsEnd();
      std::cout << t->GetNumberOfPoints() << " points = ";
      while( pit != end )
        {
        std::cout <<  *pit << "  ";
        ++pit;
        }
      std::cout << std::endl;
      }
    };
  // Software Guide : EndCodeSnippet

int main()
{

  MeshType::Pointer  mesh = MeshType::New();

  //
  // Creating the points and inserting them in the mesh
  //
  MeshType::PointType   point0;
  MeshType::PointType   point1;
  MeshType::PointType   point2;
  MeshType::PointType   point3;

  point0[0] = -1; point0[1] = -1; point0[2] = -1;
  point1[0] =  1; point1[1] =  1; point1[2] = -1;
  point2[0] =  1; point2[1] = -1; point2[2] =  1;
  point3[0] = -1; point3[1] =  1; point3[2] =  1;

  mesh->SetPoint( 0, point0 );
  mesh->SetPoint( 1, point1 );
  mesh->SetPoint( 2, point2 );
  mesh->SetPoint( 3, point3 );

  //
  // Creating and associating the Tetrahedron
  //
  CellType::CellAutoPointer cellpointer;

  cellpointer.TakeOwnership( new TetrahedronType );
  cellpointer->SetPointId( 0, 0 );
  cellpointer->SetPointId( 1, 1 );
  cellpointer->SetPointId( 2, 2 );
  cellpointer->SetPointId( 3, 3 );
  mesh->SetCell( 0, cellpointer );

  //
  // Creating and associating the Triangles
  //
  cellpointer.TakeOwnership( new TriangleType );
  cellpointer->SetPointId( 0, 0 );
  cellpointer->SetPointId( 1, 1 );
  cellpointer->SetPointId( 2, 2 );
  mesh->SetCell( 1, cellpointer );

  cellpointer.TakeOwnership( new TriangleType );
  cellpointer->SetPointId( 0, 0 );
  cellpointer->SetPointId( 1, 2 );
  cellpointer->SetPointId( 2, 3 );
  mesh->SetCell( 2, cellpointer );

  cellpointer.TakeOwnership( new TriangleType );
  cellpointer->SetPointId( 0, 0 );
  cellpointer->SetPointId( 1, 3 );
  cellpointer->SetPointId( 2, 1 );
  mesh->SetCell( 3, cellpointer );

  cellpointer.TakeOwnership( new TriangleType );
  cellpointer->SetPointId( 0, 3 );
  cellpointer->SetPointId( 1, 2 );
  cellpointer->SetPointId( 2, 1 );
  mesh->SetCell( 4, cellpointer );

  //
  // Creating and associating the Edges
  //
  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 0 );
  cellpointer->SetPointId( 1, 1 );
  mesh->SetCell( 5, cellpointer );

  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 1 );
  cellpointer->SetPointId( 1, 2 );
  mesh->SetCell( 6, cellpointer );

  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 2 );
  cellpointer->SetPointId( 1, 0 );
  mesh->SetCell( 7, cellpointer );

  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 1 );
  cellpointer->SetPointId( 1, 3 );
  mesh->SetCell( 8, cellpointer );

  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 3 );
  cellpointer->SetPointId( 1, 2 );
  mesh->SetCell( 9, cellpointer );

  cellpointer.TakeOwnership( new LineType );
  cellpointer->SetPointId( 0, 3 );
  cellpointer->SetPointId( 1, 0 );
  mesh->SetCell( 10, cellpointer );

  //
  // Creating and associating the Vertices
  //
  cellpointer.TakeOwnership( new VertexType );
  cellpointer->SetPointId( 0, 0 );
  mesh->SetCell( 11, cellpointer );

  cellpointer.TakeOwnership( new VertexType );
  cellpointer->SetPointId( 0, 1 );
  mesh->SetCell( 12, cellpointer );

  cellpointer.TakeOwnership( new VertexType );
  cellpointer->SetPointId( 0, 2 );
  mesh->SetCell( 13, cellpointer );

  cellpointer.TakeOwnership( new VertexType );
  cellpointer->SetPointId( 0, 3 );
  mesh->SetCell( 14, cellpointer );

  std::cout << "# Points= " << mesh->GetNumberOfPoints() << std::endl;
  std::cout << "# Cell  = " << mesh->GetNumberOfCells() << std::endl;

  //  Software Guide : BeginLatex
  //
  //  The cells can be visited using CellsContainer iterators . The iterator
  //  \code{Value()} corresponds to a raw pointer to the \code{CellType} base
  //  class.
  //
  // \index{itk::Mesh!CellsContainer}
  // \index{itk::Mesh!CellsIterators}
  // \index{itk::Mesh!GetCells()}
  // \index{CellsContainer!Begin()}
  // \index{CellsContainer!End()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef MeshType::CellsContainer::ConstIterator  CellIterator;

  CellIterator cellIterator = mesh->GetCells()->Begin();
  CellIterator cellEnd      = mesh->GetCells()->End();

  while( cellIterator != cellEnd )
    {
    CellType * cell = cellIterator.Value();
    std::cout << cell->GetNumberOfPoints() << std::endl;
    ++cellIterator;
    }

  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Two mechanisms can be used to safely down-cast the pointer to the actual
  //  cell type. The first is a built-in mechanism in ITK that allows the user
  //  to query the type of the Cell. Codes for the cell types have been defined
  //  with an \code{enum} type on the \code{itkCellInterface.h} header file.
  //  These codes are : VERTEX\_CELL, LINE\_CELL, TRIANGLE\_CELL,
  //  QUADRILATERAL\_CELL, POLYGON\_CELL, TETRAHEDRON\_CELL, HEXAHEDRON\_CELL,
  //  QUADRATIC\_EDGE\_CELL, QUADRATIC\_TRIANGLE\_CELL. The Cell type is returned
  //  by the method \code{GetType()}. It is then possible to test the type of
  //  the cell before down-casting its pointer to the actual type. For example,
  //  the following code visits all the cells in the mesh and test which ones
  //  are actually of type LINE\_CELL. Only those cells are down-casted to
  //  LineType cells and a method specific for the LineType are invoked.
  //
  //  Software Guide : EndLatex

  std::cout << "Visiting the Line cells : " << std::endl;

  // Software Guide : BeginCodeSnippet
  cellIterator = mesh->GetCells()->Begin();
  cellEnd      = mesh->GetCells()->End();

  while( cellIterator != cellEnd )
    {
    CellType * cell = cellIterator.Value();
    if( cell->GetType() == CellType::LINE_CELL )
      {
      LineType * line = static_cast<LineType *>( cell );
      std::cout << "dimension = " << line->GetDimension()      << std::endl;
      std::cout << "# points  = " << line->GetNumberOfPoints() << std::endl;
      }
    ++cellIterator;
    }
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  A more convinient approach for visiting the cells in the mesh is provided
  //  by the implementation of the \emph{Visitor Pattern} discussed in
  //  \cite{Gamma1995}. The visitor pattern is designed to facilitate to walk
  //  through an heterogeneous list of object sharing a common base class. A
  //  visitor class is defined and passed to the Mesh.The mesh will iterate
  //  through its cells and attempt to pass every cell to the visitor. The
  //  visitor class is capable of recognizing the cells of its interest and
  //  operation only on them.
  //
  // \index{itk::Mesh!CellInterfaceVisitorImplementation}
  // \index{itk::Mesh!CellInterfaceVisitor}
  // \index{itk::Mesh!CellVisitor}
  // \index{CellVisitor}
  //
  //  The following code illustrates how to define a cell visitor. In this
  //  particular example we create a class \code{CustomTriangleVisitor} which
  //  will be invoked each time a triangle cell is found while the mesh
  //  iterates over the cells.
  //
  //  Software Guide : EndLatex

  typedef CustomTriangleVisitor CustomVisitorType;

  // Software Guide : BeginCodeSnippet
  typedef itk::CellInterfaceVisitorImplementation<
                              PixelType,
                              MeshType::CellTraits,
                              TriangleType,
                              CustomVisitorType
                                       > TriangleVisitorInterfaceType;
  // Software Guide : EndCodeSnippet

  // Software Guide : BeginCodeSnippet
  TriangleVisitorInterfaceType::Pointer  triangleVisitor =
                                   TriangleVisitorInterfaceType::New();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  A multivisitor class must be instantiated
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef CellType::MultiVisitor CellMultiVisitorType;

  CellMultiVisitorType::Pointer multiVisitor = CellMultiVisitorType::New();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The visitor is registered with the Mesh using the \code{AddVisitor()}
  //  method.
  //
  //  \index{itk::Mesh!AddVisitor()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  multiVisitor->AddVisitor( triangleVisitor );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The iteration over the cells is triggered by calling the method
  //  \code{Accept()} on the \code{itk::Mesh}.
  //
  //  \index{itk::Mesh!Accept()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  mesh->Accept( multiVisitor );
  // Software Guide : EndCodeSnippet

  return 0;

}

<|endoftext|>