QCAD::ResponseFieldValue<EvalT, Traits>::
ResponseFieldValue(Teuchos::ParameterList& p,
                   const Teuchos::RCP<Albany::Layouts>& dl) :
  coordVec("Coord Vec", dl->qp_vector),
  weights("Weights", dl->qp_scalar)
{
  // get and validate Response parameter list
  Teuchos::ParameterList* plist =
    p.get<Teuchos::ParameterList*>("Parameter List");
  Teuchos::RCP<const Teuchos::ParameterList> reflist =
    this->getValidResponseParameters();
  plist->validateParameters(*reflist,0);

  //! parameters passed down from problem
  Teuchos::RCP<Teuchos::ParameterList> paramsFromProblem =
    p.get< Teuchos::RCP<Teuchos::ParameterList> >("Parameters From Problem");

    // Material database (if given)
  if(paramsFromProblem != Teuchos::null)
    materialDB = paramsFromProblem->get< Teuchos::RCP<QCAD::MaterialDatabase> >("MaterialDB");
  else materialDB = Teuchos::null;

  // number of quad points per cell and dimension of space
  Teuchos::RCP<PHX::DataLayout> scalar_dl = dl->qp_scalar;
  Teuchos::RCP<PHX::DataLayout> vector_dl = dl->qp_vector;

  std::vector<PHX::DataLayout::size_type> dims;
  vector_dl->dimensions(dims);
  numQPs  = dims[1];
  numDims = dims[2];

  opRegion  = Teuchos::rcp( new QCAD::MeshRegion<EvalT, Traits>("Coord Vec","Weights",*plist,materialDB,dl) );

  // User-specified parameters
  operation    = plist->get<std::string>("Operation");

  bOpFieldIsVector = false;
  if(plist->isParameter("Operation Vector Field Name")) {
    opFieldName  = plist->get<std::string>("Operation Vector Field Name");
    bOpFieldIsVector = true;
  }
  else opFieldName  = plist->get<std::string>("Operation Field Name");

  bRetFieldIsVector = false;
  if(plist->isParameter("Return Vector Field Name")) {
    retFieldName  = plist->get<std::string>("Return Vector Field Name");
    bRetFieldIsVector = true;
  }
  else retFieldName = plist->get<std::string>("Return Field Name", opFieldName);
  bReturnOpField = (opFieldName == retFieldName);

  opX = plist->get<bool>("Operate on x-component", true) && (numDims > 0);
  opY = plist->get<bool>("Operate on y-component", true) && (numDims > 1);
  opZ = plist->get<bool>("Operate on z-component", true) && (numDims > 2);

  // setup operation field and return field (if it's a different field)
  if(bOpFieldIsVector) {
    PHX::MDField<ScalarT> f(opFieldName, vector_dl); opField = f; }
  else {
    PHX::MDField<ScalarT> f(opFieldName, scalar_dl); opField = f; }

  if(!bReturnOpField) {
    if(bRetFieldIsVector) {
      PHX::MDField<ScalarT> f(retFieldName, vector_dl); retField = f; }
    else {
      PHX::MDField<ScalarT> f(retFieldName, scalar_dl); retField = f; }
  }

  // add dependent fields
  this->addDependentField(opField);
  this->addDependentField(coordVec);
  this->addDependentField(weights);
  opRegion->addDependentFields(this);
  if(!bReturnOpField) this->addDependentField(retField); //when return field is *different* from op field

  // Set sentinal values for max/min problems
  initVals = Teuchos::Array<double>(5, 0.0);
  if( operation == "Maximize" ) initVals[1] = -1e200;
  else if( operation == "Minimize" ) initVals[1] = 1e100;
  else TEUCHOS_TEST_FOR_EXCEPTION (
    true, Teuchos::Exceptions::InvalidParameter, std::endl
    << "Error!  Invalid operation type " << operation << std::endl);

  this->setName(opFieldName+" Response Field Value"+PHX::TypeString<EvalT>::value);

  // Setup scatter evaluator
  std::string global_response_name =
    opFieldName + " Global Response Field Value";
  //int worksetSize = scalar_dl->dimension(0);
  int responseSize = 5;
  Teuchos::RCP<PHX::DataLayout> global_response_layout =
    Teuchos::rcp(new PHX::MDALayout<Dim>(responseSize));
  PHX::Tag<ScalarT> global_response_tag(global_response_name,
                                        global_response_layout);
  p.set("Stand-alone Evaluator", false);
  p.set("Global Response Field Tag", global_response_tag);
  this->setup(p,dl);

  // Specify which components of response (in this case 0th and 1st) to
  //  scatter derivatives for.
  FieldValueScatterScalarResponse<EvalT,Traits>::field_components.resize(2);
  FieldValueScatterScalarResponse<EvalT,Traits>::field_components[0] = 0;
  FieldValueScatterScalarResponse<EvalT,Traits>::field_components[1] = 1;
}
QCAD::ResponseFieldIntegral<EvalT, Traits>::
ResponseFieldIntegral(Teuchos::ParameterList& p,
		      const Teuchos::RCP<Albany::Layouts>& dl) :
  coordVec("Coord Vec", dl->qp_vector),
  weights("Weights", dl->qp_scalar)
{
  //! get and validate Response parameter list
  Teuchos::ParameterList* plist = 
    p.get<Teuchos::ParameterList*>("Parameter List");
  Teuchos::RCP<const Teuchos::ParameterList> reflist = 
    this->getValidResponseParameters();
  plist->validateParameters(*reflist,0);

  //! parameters passed down from problem
  Teuchos::RCP<Teuchos::ParameterList> paramsFromProblem = 
    p.get< Teuchos::RCP<Teuchos::ParameterList> >("Parameters From Problem");
  if(paramsFromProblem != Teuchos::null) {

    // Material database 
    materialDB = paramsFromProblem->get< Teuchos::RCP<QCAD::MaterialDatabase> >("MaterialDB");

    // Length unit in meters
    length_unit_in_m = paramsFromProblem->get<double>("Length unit in m");
  }
  else {
    materialDB = Teuchos::null;
    length_unit_in_m = 1.0e-6; //default length unit = microns (backward compat)
  }
       
  //! number of quad points per cell
  Teuchos::RCP<PHX::DataLayout> scalar_dl = dl->qp_scalar;
  numQPs = scalar_dl->dimension(1);
  
  //! obtain number of dimensions
  Teuchos::RCP<PHX::DataLayout> vector_dl = dl->qp_vector;
  std::vector<PHX::DataLayout::size_type> dims;
  vector_dl->dimensions(dims);
  numDims = dims[2];

  //! Initialize Region
  opRegion  = Teuchos::rcp( new QCAD::MeshRegion<EvalT, Traits>("Coord Vec","Weights",*plist,materialDB,dl) );

  //! User-specified parameters
  std::string fieldName;

  fieldName = plist->get<std::string>("Field Name","");
  if(fieldName.length() > 0) {
    fieldNames.push_back(fieldName);
    conjugateFieldFlag.push_back(plist->get<bool>("Conjugate Field",false));

    fieldName = plist->get<std::string>("Field Name Im","");
    fieldNames_Imag.push_back(fieldName);
    if(fieldName.length() > 0) fieldIsComplex.push_back(true);
    else fieldIsComplex.push_back(false);
  }

  for(int i=1; i < QCAD::MAX_FIELDNAMES_IN_INTEGRAL; i++) {
    fieldName = plist->get<std::string>(Albany::strint("Field Name",i),"");
    if(fieldName.length() > 0) {
      fieldNames.push_back(fieldName);
      conjugateFieldFlag.push_back(plist->get<bool>(Albany::strint("Conjugate Field",i),false));

      fieldName = plist->get<std::string>(Albany::strint("Field Name Im",i),"");
      fieldNames_Imag.push_back(fieldName);
      if(fieldName.length() > 0) fieldIsComplex.push_back(true);
      else fieldIsComplex.push_back(false);
    }
    else break;
  }
  bReturnImagPart = plist->get<bool>("Return Imaginary Part",false);
  
  std::string integrandLinLengthUnit; // linear length unit of integrand (e.g. "cm" for integrand in cm^-3)
  integrandLinLengthUnit = plist->get<std::string>("Integrand Length Unit","cm");
  bPositiveOnly = plist->get<bool>("Positive Return Only",false);

  //! compute scaling factor based on number of dimensions and units
  double integrand_length_unit_in_m;
  if( integrandLinLengthUnit == "m" )       integrand_length_unit_in_m = 1.0;
  else if( integrandLinLengthUnit == "cm" ) integrand_length_unit_in_m = 1e-2;
  else if( integrandLinLengthUnit == "um" ) integrand_length_unit_in_m = 1e-6;
  else if( integrandLinLengthUnit == "nm" ) integrand_length_unit_in_m = 1e-9;
  else if( integrandLinLengthUnit == "mesh" ) integrand_length_unit_in_m = length_unit_in_m;
  else integrand_length_unit_in_m = length_unit_in_m;  // assume same unit as mesh (e.g. if unit string is blank)
  
  double X0 = length_unit_in_m / integrand_length_unit_in_m; // length scaling to get to integrand's lenght unit

  if (numDims == 1)       scaling = X0; 
  else if (numDims == 2)  scaling = X0*X0; 
  else if (numDims == 3)  scaling = X0*X0*X0; 
  else 
    TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl 
				<< "Error! Invalid number of dimensions: " << numDims << std::endl);


  //! add dependent fields (all fields assumed scalar qp)
  std::vector<std::string>::const_iterator it;
  //for(it = fieldNames.begin(); it != fieldNames.end(); ++it) {
  for(std::size_t i=0; i<fieldNames.size(); i++) {
    PHX::MDField<ScalarT,Cell,QuadPoint> f(fieldNames[i], scalar_dl);
    fields.push_back(f); this->addDependentField(f);

    PHX::MDField<ScalarT,Cell,QuadPoint> fi(fieldNames_Imag[i], scalar_dl);
    fields_Imag.push_back(fi);

    if(fieldIsComplex[i]) this->addDependentField(fi);
  }

  this->addDependentField(coordVec);
  this->addDependentField(weights);
  opRegion->addDependentFields(this);

  //TODO: make name unique? Is this needed for anything?
  this->setName(fieldName+" Response Field Integral"+PHX::TypeString<EvalT>::value);
  
  // Setup scatter evaluator
  p.set("Stand-alone Evaluator", false);
  std::string local_response_name = 
    fieldName + " Local Response Field Integral";
  std::string global_response_name = 
    fieldName + " Global Response Field Integral";
  PHX::Tag<ScalarT> local_response_tag(local_response_name, 
				       dl->cell_scalar);
  PHX::Tag<ScalarT> global_response_tag(global_response_name, 
					dl->workset_scalar);
  p.set("Local Response Field Tag", local_response_tag);
  p.set("Global Response Field Tag", global_response_tag);
  PHAL::SeparableScatterScalarResponse<EvalT,Traits>::setup(p,dl);
}
PHAL::ResponseFieldIntegral<EvalT, Traits>::
ResponseFieldIntegral(Teuchos::ParameterList& p,
		      const Teuchos::RCP<Albany::Layouts>& dl) :
  coordVec("Coord Vec", dl->qp_gradient),
  weights("Weights", dl->qp_scalar)
{
  // get and validate Response parameter list
  Teuchos::ParameterList* plist = 
    p.get<Teuchos::ParameterList*>("Parameter List");
  Teuchos::RCP<const Teuchos::ParameterList> reflist = 
    this->getValidResponseParameters();
  plist->validateParameters(*reflist,0);

  // Get field type and corresponding layouts
  std::string field_name = plist->get<std::string>("Field Name");
  std::string fieldType = plist->get<std::string>("Field Type", "Scalar");
  if (plist->isType< Teuchos::Array<int> >("Field Components"))
    field_components = plist->get< Teuchos::Array<int> >("Field Components");
  Teuchos::RCP<PHX::DataLayout> field_layout;
  Teuchos::RCP<PHX::DataLayout> local_response_layout;
  Teuchos::RCP<PHX::DataLayout> global_response_layout;
  if (fieldType == "Scalar") {
    field_layout = dl->qp_scalar;
    local_response_layout = dl->cell_scalar;
    global_response_layout = dl->workset_scalar;
  }
  else if (fieldType == "Vector") {
    field_layout = dl->qp_vector;
    if (field_components.size() == 0) {
      local_response_layout = dl->cell_vector;
      global_response_layout = dl->workset_vector;
    }
    else {
      int worksetSize = dl->cell_scalar->dimension(0);
      local_response_layout = 
	Teuchos::rcp(new PHX::MDALayout<Cell,Dim>(worksetSize, 
						  field_components.size()));
      global_response_layout = 
	Teuchos::rcp(new PHX::MDALayout<Dim>(field_components.size()));
    }
  }
  else if (fieldType == "Tensor") {
    TEUCHOS_TEST_FOR_EXCEPTION(
      true, std::logic_error,
      "local_ and global_response must have rank 2. However, this code path "
      "makes them rank 3. Needs to be fixed.");
    field_layout = dl->qp_tensor;
    local_response_layout = dl->cell_tensor;
    global_response_layout = dl->workset_tensor;
  }
  else {
    TEUCHOS_TEST_FOR_EXCEPTION(
      true, 
      Teuchos::Exceptions::InvalidParameter,
      "Invalid field type " << fieldType << ".  Support values are " << 
      "Scalar, Vector, and Tensor." << std::endl);
  }
  field = PHX::MDField<ScalarT>(field_name, field_layout);
  field_layout->dimensions(field_dims);
  field_rank = field_layout->rank();
  if (field_components.size() == 0) {
    int num_components = field_dims[field_rank-1];
    field_components.resize(num_components);
    for (int i=0; i<num_components; i++)
      field_components[i] = i;
  }

  // coordinate dimensions
  std::vector<PHX::DataLayout::size_type> coord_dims;
  dl->qp_vector->dimensions(coord_dims);
  numQPs = coord_dims[1];
  numDims = coord_dims[2];
 
  // User-specified parameters
  std::string ebNameStr = plist->get<std::string>("Element Block Name","");
  if(ebNameStr.length() > 0) split(ebNameStr,',',ebNames);

  limitX = limitY = limitZ = false;
  if( plist->isParameter("x min") && plist->isParameter("x max") ) {
    limitX = true; TEUCHOS_TEST_FOR_EXCEPT(numDims <= 0);
    xmin = plist->get<double>("x min");
    xmax = plist->get<double>("x max");
  }
  if( plist->isParameter("y min") && plist->isParameter("y max") ) {
    limitY = true; TEUCHOS_TEST_FOR_EXCEPT(numDims <= 1);
    ymin = plist->get<double>("y min");
    ymax = plist->get<double>("y max");
  }
  if( plist->isParameter("z min") && plist->isParameter("z max") ) {
    limitZ = true; TEUCHOS_TEST_FOR_EXCEPT(numDims <= 2);
    zmin = plist->get<double>("z min");
    zmax = plist->get<double>("z max");
  }

  // length scaling
  double X0 = plist->get<double>("Length Scaling", 1.0);
  if (numDims == 1)
    scaling = X0; 
  else if (numDims == 2)
    scaling = X0*X0; 
  else if (numDims == 3)
    scaling = X0*X0*X0; 
  else      
    TEUCHOS_TEST_FOR_EXCEPTION(
      true, Teuchos::Exceptions::InvalidParameter, 
      std::endl << "Error! Invalid number of dimensions: " << numDims << 
      std::endl);

  // add dependent fields
  this->addDependentField(field);
  this->addDependentField(coordVec);
  this->addDependentField(weights);
  this->setName(field_name+" Response Field Integral"+PHX::typeAsString<EvalT>());

  // Setup scatter evaluator
  p.set("Stand-alone Evaluator", false);
  std::string local_response_name = 
    field_name + " Local Response Field Integral";
  std::string global_response_name = 
    field_name + " Global Response Field Integral";
  PHX::Tag<ScalarT> local_response_tag(local_response_name, 
				       local_response_layout);
  PHX::Tag<ScalarT> global_response_tag(global_response_name, 
					global_response_layout);
  p.set("Local Response Field Tag", local_response_tag);
  p.set("Global Response Field Tag", global_response_tag);
  PHAL::SeparableScatterScalarResponse<EvalT,Traits>::setup(p,dl);
}