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

  Program:   Visualization Toolkit
  Module:    vtkGraphLayout.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/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 notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkGraphLayout.h"

#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkDataArray.h>
#include <vtkEventForwarderCommand.h>
#include <vtkFloatArray.h>
#include <vtkMath.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>

#include "vtkGraphLayoutStrategy.h"

vtkCxxRevisionMacro(vtkGraphLayout, "1.6");
vtkStandardNewMacro(vtkGraphLayout);

// ----------------------------------------------------------------------

vtkGraphLayout::vtkGraphLayout()
{
  this->LayoutStrategy = 0;
  this->LastInput = NULL;
  this->LastInputMTime = 0;
  this->InternalGraph = NULL;

  this->ObserverTag = 0;
  this->EventForwarder = vtkEventForwarderCommand::New();
  this->EventForwarder->SetTarget(this);
}

// ----------------------------------------------------------------------

vtkGraphLayout::~vtkGraphLayout()
{
  if (this->LayoutStrategy)
    {
    this->LayoutStrategy->Delete();
    }
  if (this->InternalGraph)
    {
    this->InternalGraph->Delete();
    }
  this->EventForwarder->Delete();
}

// ----------------------------------------------------------------------

void
vtkGraphLayout::SetLayoutStrategy(vtkGraphLayoutStrategy *strategy)
{
  // This method is a cut and paste of vtkCxxSetObjectMacro
  // except for the call to SetGraph in the middle :)
  if (strategy != this->LayoutStrategy)
    {
    vtkGraphLayoutStrategy *tmp = this->LayoutStrategy;
    this->LayoutStrategy = strategy;
    if (this->LayoutStrategy != NULL)
      {
      this->StrategyChanged = true;
      this->LayoutStrategy->Register(this);
      this->ObserverTag =
        this->LayoutStrategy->AddObserver(vtkCommand::ProgressEvent,
                                          this->EventForwarder);
      if (this->InternalGraph)
        {
        // Set the graph in the layout strategy
        this->LayoutStrategy->SetGraph(this->InternalGraph);
        }
      }
    if (tmp != NULL)
      {
      tmp->RemoveObserver(this->ObserverTag);
      tmp->UnRegister(this);
      }
    this->Modified();
    }

}

// ----------------------------------------------------------------------

unsigned long
vtkGraphLayout::GetMTime()
{
  unsigned long mTime = this->Superclass::GetMTime();
  unsigned long time;

  if (this->LayoutStrategy != NULL)
    {
    time = this->LayoutStrategy->GetMTime();
    mTime = (time > mTime ? time : mTime);
    }
  return mTime;
}

// ----------------------------------------------------------------------

int
vtkGraphLayout::IsLayoutComplete()
{
  if (this->LayoutStrategy)
    {
    return this->LayoutStrategy->IsLayoutComplete();
    }

  // This is an error condition
  vtkErrorMacro("IsLayoutComplete called with layout strategy==NULL");
  return 0;
}

// ----------------------------------------------------------------------

int
vtkGraphLayout::RequestData(vtkInformation *vtkNotUsed(request),
                            vtkInformationVector **inputVector,
                            vtkInformationVector *outputVector)
{
  if (this->LayoutStrategy == NULL)
    {
    vtkErrorMacro(<< "Layout strategy must be non-null.");
    return 0;
    }

  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and output
  vtkAbstractGraph *input = vtkAbstractGraph::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkAbstractGraph *output = vtkAbstractGraph::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  // Is this a completely new input?  Is it the same input as the last
  // time the filter ran but with a new MTime?  If either of those is
  // true, make a copy and give it to the strategy object anew.
  if (this->StrategyChanged ||
      input != this->LastInput ||
      input->GetMTime() > this->LastInputMTime)
    {
    if (this->StrategyChanged)
      {
      vtkDebugMacro(<<"Strategy changed so reading in input again.");
      this->StrategyChanged = false;
      }
    else if (input != this->LastInput)
      {
      vtkDebugMacro(<<"Filter running with different input.  Resetting in strategy.");
      }
    else
      {
      vtkDebugMacro(<<"Input modified since last run.  Resetting in strategy.");
      }

    if (this->InternalGraph)
      {
      this->InternalGraph->Delete();
      }

    this->InternalGraph = input->NewInstance();
    // The strategy object is going to modify the Points member so
    // we'll replace that with a deep copy.  For everything else a
    // shallow copy is sufficient.
    this->InternalGraph->ShallowCopy(input);
    vtkPoints* newPoints = vtkPoints::New();
    newPoints->DeepCopy(input->GetPoints());
    this->InternalGraph->SetPoints(newPoints);
    newPoints->Delete();

    // Save information about the input so that we can detect when
    // it's changed on future runs.  According to the VTK pipeline
    // design, this is a bad thing.  In this case there's no
    // particularly graceful way around it since the pipeline was not
    // designed to support incremental execution.
    this->LastInput = input;
    this->LastInputMTime = input->GetMTime();

    // Give the layout strategy a pointer to the input.  We set it to
    // NULL first to force the layout algorithm to re-initialize
    // itself.  This is necessary in case the input is the same data
    // object with a newer mtime.
    this->LayoutStrategy->SetGraph(NULL);
    this->LayoutStrategy->SetGraph(this->InternalGraph);
    } // Done handling a new or changed filter input.

  // No matter whether the input is new or not, the layout strategy
  // needs to do its thing.  It modifies its input
  // (this->InternalGraph) so we can just use that as the output.
  this->LayoutStrategy->Layout();
  output->ShallowCopy(this->InternalGraph);

  return 1;
}

// ----------------------------------------------------------------------

void vtkGraphLayout::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "StrategyChanged: " << (this->StrategyChanged ? "True" : "False") << endl;
  os << indent << "LayoutStrategy: " << (this->LayoutStrategy ? "" : "(none)") << endl;
  if (this->LayoutStrategy)
    {
    this->LayoutStrategy->PrintSelf(os, indent.GetNextIndent());
    }
  os << indent << "InternalGraph: " << (this->InternalGraph ? "" : "(none)") << endl;
  if (this->InternalGraph)
    {
    this->InternalGraph->PrintSelf(os, indent.GetNextIndent());
    }
}
<commit_msg>STYLE: This change doesn't ^actually^ change the code, but does make explicit the fact the vtkPoints is constructed by default with a float array.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkGraphLayout.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/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 notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkGraphLayout.h"

#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkDataArray.h>
#include <vtkEventForwarderCommand.h>
#include <vtkFloatArray.h>
#include <vtkMath.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>

#include "vtkGraphLayoutStrategy.h"

vtkCxxRevisionMacro(vtkGraphLayout, "1.7");
vtkStandardNewMacro(vtkGraphLayout);

// ----------------------------------------------------------------------

vtkGraphLayout::vtkGraphLayout()
{
  this->LayoutStrategy = 0;
  this->LastInput = NULL;
  this->LastInputMTime = 0;
  this->InternalGraph = NULL;

  this->ObserverTag = 0;
  this->EventForwarder = vtkEventForwarderCommand::New();
  this->EventForwarder->SetTarget(this);
}

// ----------------------------------------------------------------------

vtkGraphLayout::~vtkGraphLayout()
{
  if (this->LayoutStrategy)
    {
    this->LayoutStrategy->Delete();
    }
  if (this->InternalGraph)
    {
    this->InternalGraph->Delete();
    }
  this->EventForwarder->Delete();
}

// ----------------------------------------------------------------------

void
vtkGraphLayout::SetLayoutStrategy(vtkGraphLayoutStrategy *strategy)
{
  // This method is a cut and paste of vtkCxxSetObjectMacro
  // except for the call to SetGraph in the middle :)
  if (strategy != this->LayoutStrategy)
    {
    vtkGraphLayoutStrategy *tmp = this->LayoutStrategy;
    this->LayoutStrategy = strategy;
    if (this->LayoutStrategy != NULL)
      {
      this->StrategyChanged = true;
      this->LayoutStrategy->Register(this);
      this->ObserverTag =
        this->LayoutStrategy->AddObserver(vtkCommand::ProgressEvent,
                                          this->EventForwarder);
      if (this->InternalGraph)
        {
        // Set the graph in the layout strategy
        this->LayoutStrategy->SetGraph(this->InternalGraph);
        }
      }
    if (tmp != NULL)
      {
      tmp->RemoveObserver(this->ObserverTag);
      tmp->UnRegister(this);
      }
    this->Modified();
    }

}

// ----------------------------------------------------------------------

unsigned long
vtkGraphLayout::GetMTime()
{
  unsigned long mTime = this->Superclass::GetMTime();
  unsigned long time;

  if (this->LayoutStrategy != NULL)
    {
    time = this->LayoutStrategy->GetMTime();
    mTime = (time > mTime ? time : mTime);
    }
  return mTime;
}

// ----------------------------------------------------------------------

int
vtkGraphLayout::IsLayoutComplete()
{
  if (this->LayoutStrategy)
    {
    return this->LayoutStrategy->IsLayoutComplete();
    }

  // This is an error condition
  vtkErrorMacro("IsLayoutComplete called with layout strategy==NULL");
  return 0;
}

// ----------------------------------------------------------------------

int
vtkGraphLayout::RequestData(vtkInformation *vtkNotUsed(request),
                            vtkInformationVector **inputVector,
                            vtkInformationVector *outputVector)
{
  if (this->LayoutStrategy == NULL)
    {
    vtkErrorMacro(<< "Layout strategy must be non-null.");
    return 0;
    }

  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and output
  vtkAbstractGraph *input = vtkAbstractGraph::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkAbstractGraph *output = vtkAbstractGraph::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  // Is this a completely new input?  Is it the same input as the last
  // time the filter ran but with a new MTime?  If either of those is
  // true, make a copy and give it to the strategy object anew.
  if (this->StrategyChanged ||
      input != this->LastInput ||
      input->GetMTime() > this->LastInputMTime)
    {
    if (this->StrategyChanged)
      {
      vtkDebugMacro(<<"Strategy changed so reading in input again.");
      this->StrategyChanged = false;
      }
    else if (input != this->LastInput)
      {
      vtkDebugMacro(<<"Filter running with different input.  Resetting in strategy.");
      }
    else
      {
      vtkDebugMacro(<<"Input modified since last run.  Resetting in strategy.");
      }

    if (this->InternalGraph)
      {
      this->InternalGraph->Delete();
      }

    this->InternalGraph = input->NewInstance();
    // The strategy object is going to modify the Points member so
    // we'll replace that with a deep copy.  For everything else a
    // shallow copy is sufficient.
    this->InternalGraph->ShallowCopy(input);

    // The copy of the points will be to a float type
    vtkPoints* newPoints = vtkPoints::New(VTK_FLOAT);
    newPoints->DeepCopy(input->GetPoints());
    this->InternalGraph->SetPoints(newPoints);
    newPoints->Delete();

    // Save information about the input so that we can detect when
    // it's changed on future runs.  According to the VTK pipeline
    // design, this is a bad thing.  In this case there's no
    // particularly graceful way around it since the pipeline was not
    // designed to support incremental execution.
    this->LastInput = input;
    this->LastInputMTime = input->GetMTime();

    // Give the layout strategy a pointer to the input.  We set it to
    // NULL first to force the layout algorithm to re-initialize
    // itself.  This is necessary in case the input is the same data
    // object with a newer mtime.
    this->LayoutStrategy->SetGraph(NULL);
    this->LayoutStrategy->SetGraph(this->InternalGraph);
    } // Done handling a new or changed filter input.

  // No matter whether the input is new or not, the layout strategy
  // needs to do its thing.  It modifies its input
  // (this->InternalGraph) so we can just use that as the output.
  this->LayoutStrategy->Layout();
  output->ShallowCopy(this->InternalGraph);

  return 1;
}

// ----------------------------------------------------------------------

void vtkGraphLayout::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "StrategyChanged: " << (this->StrategyChanged ? "True" : "False") << endl;
  os << indent << "LayoutStrategy: " << (this->LayoutStrategy ? "" : "(none)") << endl;
  if (this->LayoutStrategy)
    {
    this->LayoutStrategy->PrintSelf(os, indent.GetNextIndent());
    }
  os << indent << "InternalGraph: " << (this->InternalGraph ? "" : "(none)") << endl;
  if (this->InternalGraph)
    {
    this->InternalGraph->PrintSelf(os, indent.GetNextIndent());
    }
}
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <gtest/gtest.h>

#include <Core/Datatypes/Legacy/Field/VField.h>
#include <Core/Datatypes/Legacy/Field/FieldInformation.h>
#include <Core/Datatypes/Matrix.h>
#include <Core/Algorithms/Legacy/Fields/Mapping/MapFieldDataFromNodeToElem.h>
#include <Testing/Utils/SCIRunUnitTests.h>
#include <Core/Datatypes/DenseMatrix.h>
#include <Core/Algorithms/Base/AlgorithmPreconditions.h>
#include <Testing/Utils/MatrixTestUtilities.h>

using namespace SCIRun;
using namespace SCIRun::Core::Datatypes;
using namespace SCIRun::Core::Geometry;
using namespace SCIRun::Core::Algorithms::Fields;
using namespace SCIRun::TestUtils;

  FieldHandle CreateTetMesh1()
  {
   return loadFieldFromFile(TestResources::rootDir() / "Fields/test_mapfielddatafromelemtonode.fld");
  }

  FieldHandle CreateTetMesh2()
  {
   return loadFieldFromFile(TestResources::rootDir() / "Fields/test_mapfielddatafromnodetoelem.fld");
  }

  DenseMatrixHandle test_MapFieldDataFromNodeToElemFLD_IntAvr()
  {
    return MAKE_DENSE_MATRIX_HANDLE(
      (3.325000000000000177635684,0)
      (3.29166666666666651863693,0)
      (3.533333333333333214909544,0)
      (3.325000000000000177635684,0)
      (3.741666666666666252183404,0)
      (3.783333333333333214909544,0));
  }

  DenseMatrixHandle test_mapfielddatafromnodetoelemFLD_Min()
  {
    return MAKE_DENSE_MATRIX_HANDLE(
      (2.5,0)
      (2,0)
      (3.33333333333333333333333333,0)
      (2.5,0)
      (3.33333333333333333333333333,0)
      (3.5,0));
  }

  DenseMatrixHandle test_mapfielddatafromnodetoelemFLD_Max()
  {
    return MAKE_DENSE_MATRIX_HANDLE(
      (3.8,0)
      (4.33333333333333333333333333,0)
      (3.8,0)
      (3.8,0)
      (4.33333333333333333333333333,0)
      (4.33333333333333333333333333,0));
  }

  DenseMatrixHandle test_mapfielddatafromnodetoelemFLD_Sum()
  {
    return MAKE_DENSE_MATRIX_HANDLE(
      (13.3,0)
      (13.1666666666666666666666666,0)
      (14.1333333333333333333333333,0)
      (13.3,0)
      (14.9666666666666666666666666,0)
      (15.1333333333333333333333333,0));
  }

  DenseMatrixHandle test_mapfielddatafromnodetoelemFLD_Med()
  {
    return MAKE_DENSE_MATRIX_HANDLE(
      (3.5,0)
      (3.5,0)
      (3.5,0)
      (3.5,0)
      (3.8,0)
      (3.8,0));
  }

TEST(MapFieldDataFromNodeToElemAlgoTests,TestInterpolationAverage)
{
 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Average");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result = algo.run(input);

 DenseMatrixHandle expected=test_MapFieldDataFromNodeToElemFLD_IntAvr();

 ASSERT_TRUE(result->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Interpolation");

 FieldHandle input2=CreateTetMesh2();

 FieldHandle result2 = algo.run(input);

 ASSERT_TRUE(result2->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result2->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result2->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestDataAlreadyOnElems)
{

 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Average");

 FieldHandle input=CreateTetMesh1();

 FieldHandle result;
 try
 {
  result = algo.run(input);
 } catch (...) {}

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestMin)
{
 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Min");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result = algo.run(input);

 DenseMatrixHandle expected=test_mapfielddatafromnodetoelemFLD_Min();

 ASSERT_TRUE(result->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestMax)
{

 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Max");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result = algo.run(input);

 DenseMatrixHandle expected=test_mapfielddatafromnodetoelemFLD_Max();

 ASSERT_TRUE(result->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestSum)
{

 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Sum");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result = algo.run(input);

 DenseMatrixHandle expected=test_mapfielddatafromnodetoelemFLD_Sum();

 ASSERT_TRUE(result->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestMedian)
{

 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Median");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result = algo.run(input);

 DenseMatrixHandle expected=test_mapfielddatafromnodetoelemFLD_Med();

 ASSERT_TRUE(result->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestNone)
{

 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "None");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result;
 try
 {
  result = algo.run(input);
 } catch (...) {}

 if(result)
 {
   FAIL() << " ERROR: THIS MESSAGE SHOULD NOT APPEAR! " << std::endl;
 }

}
<commit_msg>Gcc fix<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <gtest/gtest.h>

#include <Core/Datatypes/Legacy/Field/VField.h>
#include <Core/Datatypes/Legacy/Field/FieldInformation.h>
#include <Core/Datatypes/Matrix.h>
#include <Core/Algorithms/Legacy/Fields/Mapping/MapFieldDataFromNodeToElem.h>
#include <Testing/Utils/SCIRunUnitTests.h>
#include <Core/Datatypes/DenseMatrix.h>
#include <Core/Algorithms/Base/AlgorithmPreconditions.h>
#include <Testing/Utils/MatrixTestUtilities.h>

using namespace SCIRun;
using namespace SCIRun::Core::Datatypes;
using namespace SCIRun::Core::Geometry;
using namespace SCIRun::Core::Algorithms::Fields;
using namespace SCIRun::TestUtils;

  FieldHandle CreateTetMesh1()
  {
   return loadFieldFromFile(TestResources::rootDir() / "Fields/test_mapfielddatafromelemtonode.fld");
  }

  FieldHandle CreateTetMesh2()
  {
   return loadFieldFromFile(TestResources::rootDir() / "Fields/test_mapfielddatafromnodetoelem.fld");
  }

  DenseMatrixHandle test_MapFieldDataFromNodeToElemFLD_IntAvr()
  {
    return MAKE_DENSE_MATRIX_HANDLE(
      (3.325000000000000177635684,0)
      (3.29166666666666651863693,0)
      (3.533333333333333214909544,0)
      (3.325000000000000177635684,0)
      (3.741666666666666252183404,0)
      (3.783333333333333214909544,0));
  }

  DenseMatrixHandle test_mapfielddatafromnodetoelemFLD_Min()
  {
    return MAKE_DENSE_MATRIX_HANDLE(
      (2.5,0.0)
      (2.0,0.0)
      (3.33333333333333333333333333,0.0)
      (2.5,0.0)
      (3.33333333333333333333333333,0.0)
      (3.5,0.0));
  }

  DenseMatrixHandle test_mapfielddatafromnodetoelemFLD_Max()
  {
    return MAKE_DENSE_MATRIX_HANDLE(
      (3.8,0.0)
      (4.33333333333333333333333333,0.0)
      (3.8,0.0)
      (3.8,0.0)
      (4.33333333333333333333333333,0.0)
      (4.33333333333333333333333333,0.0));
  }

  DenseMatrixHandle test_mapfielddatafromnodetoelemFLD_Sum()
  {
    return MAKE_DENSE_MATRIX_HANDLE(
      (13.3,0.0)
      (13.1666666666666666666666666,0.0)
      (14.1333333333333333333333333,0.0)
      (13.3,0.0)
      (14.9666666666666666666666666,0.0)
      (15.1333333333333333333333333,0.0));
  }

  DenseMatrixHandle test_mapfielddatafromnodetoelemFLD_Med()
  {
    return MAKE_DENSE_MATRIX_HANDLE(
      (3.5,0.0)
      (3.5,0.0)
      (3.5,0.0)
      (3.5,0.0)
      (3.8,0.0)
      (3.8,0.0));
  }

TEST(MapFieldDataFromNodeToElemAlgoTests,TestInterpolationAverage)
{
 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Average");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result = algo.run(input);

 DenseMatrixHandle expected=test_MapFieldDataFromNodeToElemFLD_IntAvr();

 ASSERT_TRUE(result->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Interpolation");

 FieldHandle input2=CreateTetMesh2();

 FieldHandle result2 = algo.run(input);

 ASSERT_TRUE(result2->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result2->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result2->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestDataAlreadyOnElems)
{

 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Average");

 FieldHandle input=CreateTetMesh1();

 FieldHandle result;
 try
 {
  result = algo.run(input);
 } catch (...) {}

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestMin)
{
 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Min");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result = algo.run(input);

 DenseMatrixHandle expected=test_mapfielddatafromnodetoelemFLD_Min();

 ASSERT_TRUE(result->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestMax)
{

 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Max");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result = algo.run(input);

 DenseMatrixHandle expected=test_mapfielddatafromnodetoelemFLD_Max();

 ASSERT_TRUE(result->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestSum)
{

 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Sum");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result = algo.run(input);

 DenseMatrixHandle expected=test_mapfielddatafromnodetoelemFLD_Sum();

 ASSERT_TRUE(result->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestMedian)
{

 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "Median");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result = algo.run(input);

 DenseMatrixHandle expected=test_mapfielddatafromnodetoelemFLD_Med();

 ASSERT_TRUE(result->vfield()->num_values() == 6);

 for (VMesh::Elem::index_type idx = 0; idx < result->vfield()->num_values(); idx++)
 {
   double tmp=0;
   result->vfield()->get_value(tmp,idx);
   EXPECT_NEAR( (*expected)(idx,0),tmp, 1e-5);
 }

}

TEST(MapFieldDataFromNodeToElemAlgoTests, TestNone)
{

 MapFieldDataFromNodeToElemAlgo algo;

 algo.set_option(MapFieldDataFromNodeToElemAlgo::Method, "None");

 FieldHandle input=CreateTetMesh2();

 FieldHandle result;
 try
 {
  result = algo.run(input);
 } catch (...) {}

 if(result)
 {
   FAIL() << " ERROR: THIS MESSAGE SHOULD NOT APPEAR! " << std::endl;
 }

}
<|endoftext|>


<commit_before>// $Id$

// The libMesh Finite Element Library.
// Copyright (C) 2002-2008 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

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

// This library 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh_common.h"

#ifdef LIBMESH_HAVE_PETSC

// C++ includes

// Local Includes
#include "nonlinear_implicit_system.h"
#include "petsc_nonlinear_solver.h"
#include "petsc_linear_solver.h"
#include "petsc_vector.h"
#include "petsc_matrix.h"
#include "system.h"
#include "dof_map.h"
#include "preconditioner.h"

//--------------------------------------------------------------------
// Functions with C linkage to pass to PETSc.  PETSc will call these
// methods as needed.
//
// Since they must have C linkage they have no knowledge of a namespace.
// Give them an obscure name to avoid namespace pollution.
extern "C"
{
  // Older versions of PETSc do not have the different int typedefs.
  // On 64-bit machines, PetscInt may actually be a long long int.
  // This change occurred in Petsc-2.2.1.
#if PETSC_VERSION_LESS_THAN(2,2,1)
  typedef int PetscErrorCode;
  typedef int PetscInt;
#endif

  //-------------------------------------------------------------------
  // this function is called by PETSc at the end of each nonlinear step
  PetscErrorCode
  __libmesh_petsc_snes_monitor (SNES, PetscInt its, PetscReal fnorm, void *)
  {
    //int ierr=0;

    //if (its > 0)
      std::cout << "  NL step " << its
		<< std::scientific
		<< ", |residual|_2 = " << fnorm
		<< std::endl;

    //return ierr;
    return 0;
  }

  //---------------------------------------------------------------
  // this function is called by PETSc to evaluate the residual at X
  PetscErrorCode
  __libmesh_petsc_snes_residual (SNES, Vec x, Vec r, void *ctx)
  {
    int ierr=0;

    libmesh_assert (x   != NULL);
    libmesh_assert (r   != NULL);
    libmesh_assert (ctx != NULL);

    PetscNonlinearSolver<Number>* solver =
      static_cast<PetscNonlinearSolver<Number>*> (ctx);

    NonlinearImplicitSystem &sys = solver->system();

    PetscVector<Number> X_global(x), R(r);
    PetscVector<Number>& X_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
    PetscVector<Number>& R_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.rhs);

    // Use the systems update() to get a good local version of the parallel solution
    X_global.swap(X_sys);
    R.swap(R_sys);

    sys.get_dof_map().enforce_constraints_exactly(sys);

    sys.update();

    //Swap back
    X_global.swap(X_sys);
    R.swap(R_sys);

    R.zero();

    if      (solver->residual != NULL) solver->residual (*sys.current_local_solution.get(), R);
    else if (solver->matvec   != NULL) solver->matvec   (*sys.current_local_solution.get(), &R, NULL);
    else libmesh_error();

    R.close();
    X_global.close();

    return ierr;
  }

  //---------------------------------------------------------------
  // this function is called by PETSc to evaluate the Jacobian at X
  PetscErrorCode
  __libmesh_petsc_snes_jacobian (SNES, Vec x, Mat *jac, Mat *pc, MatStructure *msflag, void *ctx)
  {
    int ierr=0;

    libmesh_assert (ctx != NULL);

    PetscNonlinearSolver<Number>* solver =
      static_cast<PetscNonlinearSolver<Number>*> (ctx);

    NonlinearImplicitSystem &sys = solver->system();

    PetscMatrix<Number> PC(*pc);
    PetscMatrix<Number> Jac(*jac);
    PetscVector<Number> X_global(x);
    PetscVector<Number>& X_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
    PetscMatrix<Number>& Jac_sys = *libmesh_cast_ptr<PetscMatrix<Number>*>(sys.matrix);

    // Use the systems update() to get a good local version of the parallel solution
    X_global.swap(X_sys);
    Jac.swap(Jac_sys);

    sys.get_dof_map().enforce_constraints_exactly(sys);
    sys.update();

    X_global.swap(X_sys);
    Jac.swap(Jac_sys);

    PC.zero();

    if      (solver->jacobian != NULL) solver->jacobian (*sys.current_local_solution.get(), PC);
    else if (solver->matvec   != NULL) solver->matvec   (*sys.current_local_solution.get(), NULL, &PC);
    else libmesh_error();

    PC.close();
    Jac.close();
    X_global.close();

    *msflag = SAME_NONZERO_PATTERN;

    return ierr;
  }

} // end extern "C"
//---------------------------------------------------------------------

//---------------------------------------------------------------------
// PetscNonlinearSolver<> methods
template <typename T>
void PetscNonlinearSolver<T>::clear ()
{
  if (this->initialized())
    {
      this->_is_initialized = false;

      int ierr=0;

      ierr = SNESDestroy(_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }
}

template <typename T>
void PetscNonlinearSolver<T>::init ()
{
  // Initialize the data structures if not done so already.
  if (!this->initialized())
    {
      this->_is_initialized = true;

      int ierr=0;

#if PETSC_VERSION_LESS_THAN(2,1,2)
      // At least until Petsc 2.1.1, the SNESCreate had a different calling syntax.
      // The second argument was of type SNESProblemType, and could have a value of
      // either SNES_NONLINEAR_EQUATIONS or SNES_UNCONSTRAINED_MINIMIZATION.
      ierr = SNESCreate(libMesh::COMM_WORLD, SNES_NONLINEAR_EQUATIONS, &_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

#else

      ierr = SNESCreate(libMesh::COMM_WORLD,&_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

#endif

#if PETSC_VERSION_LESS_THAN(2,3,3)
      ierr = SNESSetMonitor (_snes, __libmesh_petsc_snes_monitor,
			     this, PETSC_NULL);
#else
      // API name change in PETSc 2.3.3
      ierr = SNESMonitorSet (_snes, __libmesh_petsc_snes_monitor,
			     this, PETSC_NULL);
#endif
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

      ierr = SNESSetFromOptions(_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

      if(this->_preconditioner)
      {
        KSP ksp;
        ierr = SNESGetKSP (_snes, &ksp);
               CHKERRABORT(libMesh::COMM_WORLD,ierr);
        PC pc;
        ierr = KSPGetPC(ksp,&pc);
               CHKERRABORT(libMesh::COMM_WORLD,ierr);

        PCSetType(pc, PCSHELL);
        PCShellSetContext(pc,(void*)this->_preconditioner);

        //Re-Use the shell functions from petsc_linear_solver
        PCShellSetSetUp(pc,__libmesh_petsc_preconditioner_setup);
        PCShellSetApply(pc,__libmesh_petsc_preconditioner_apply);
      }
    }
}

template <typename T>
std::pair<unsigned int, Real>
PetscNonlinearSolver<T>::solve (SparseMatrix<T>&  jac_in,  // System Jacobian Matrix
				NumericVector<T>& x_in,    // Solution vector
				NumericVector<T>& r_in,    // Residual vector
				const double,              // Stopping tolerance
				const unsigned int)
{
  this->init ();

  // Make sure the data passed in are really of Petsc types
  PetscMatrix<T>* jac = libmesh_cast_ptr<PetscMatrix<T>*>(&jac_in);
  PetscVector<T>* x   = libmesh_cast_ptr<PetscVector<T>*>(&x_in);
  PetscVector<T>* r   = libmesh_cast_ptr<PetscVector<T>*>(&r_in);

  int ierr=0;
  int n_iterations =0;

  ierr = SNESSetFunction (_snes, r->vec(), __libmesh_petsc_snes_residual, this);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = SNESSetJacobian (_snes, jac->mat(), jac->mat(), __libmesh_petsc_snes_jacobian, this);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

   // Have the Krylov subspace method use our good initial guess rather than 0
   KSP ksp;
   ierr = SNESGetKSP (_snes, &ksp);
          CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Set the tolerances for the iterative solver.  Use the user-supplied
  // tolerance for the relative residual & leave the others at default values
  ierr = KSPSetTolerances (ksp, this->initial_linear_tolerance, PETSC_DEFAULT,
                           PETSC_DEFAULT, this->max_linear_iterations);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Set the tolerances for the non-linear solver.
  ierr = SNESSetTolerances(_snes, this->absolute_residual_tolerance, this->relative_residual_tolerance,
                           this->absolute_step_tolerance, this->max_nonlinear_iterations, this->max_function_evaluations);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  //Pull in command-line options
  KSPSetFromOptions(ksp);
  SNESSetFromOptions(_snes);

  //Set the preconditioning matrix
  if(this->_preconditioner)
    this->_preconditioner->set_matrix(jac_in);

//    ierr = KSPSetInitialGuessNonzero (ksp, PETSC_TRUE);
//           CHKERRABORT(libMesh::COMM_WORLD,ierr);

// Older versions (at least up to 2.1.5) of SNESSolve took 3 arguments,
// the last one being a pointer to an int to hold the number of iterations required.
# if PETSC_VERSION_LESS_THAN(2,2,0)

 ierr = SNESSolve (_snes, x->vec(), &n_iterations);
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

// 2.2.x style
#elif PETSC_VERSION_LESS_THAN(2,3,0)

 ierr = SNESSolve (_snes, x->vec());
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

// 2.3.x & newer style
#else

 ierr = SNESSolve (_snes, PETSC_NULL, x->vec());
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

#endif

  SNESConvergedReason reason;
  SNESGetConvergedReason(_snes,&reason);

  //Based on Petsc 2.3.3 documentation all diverged reasons are negative
  this->converged = reason >= 0;

  this->clear();

  // return the # of its. and the final residual norm.  Note that
  // n_iterations may be zero for PETSc versions 2.2.x and greater.
  return std::make_pair(n_iterations, 0.);
}

//------------------------------------------------------------------
// Explicit instantiations
template class PetscNonlinearSolver<Number>;

#endif // #ifdef LIBMESH_HAVE_PETSC
<commit_msg>print nonlinear iteration count as a fixed width for aesthetics<commit_after>// $Id$

// The libMesh Finite Element Library.
// Copyright (C) 2002-2008 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

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

// This library 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh_common.h"

#ifdef LIBMESH_HAVE_PETSC

// C++ includes

// Local Includes
#include "nonlinear_implicit_system.h"
#include "petsc_nonlinear_solver.h"
#include "petsc_linear_solver.h"
#include "petsc_vector.h"
#include "petsc_matrix.h"
#include "system.h"
#include "dof_map.h"
#include "preconditioner.h"

//--------------------------------------------------------------------
// Functions with C linkage to pass to PETSc.  PETSc will call these
// methods as needed.
//
// Since they must have C linkage they have no knowledge of a namespace.
// Give them an obscure name to avoid namespace pollution.
extern "C"
{
  // Older versions of PETSc do not have the different int typedefs.
  // On 64-bit machines, PetscInt may actually be a long long int.
  // This change occurred in Petsc-2.2.1.
#if PETSC_VERSION_LESS_THAN(2,2,1)
  typedef int PetscErrorCode;
  typedef int PetscInt;
#endif

  //-------------------------------------------------------------------
  // this function is called by PETSc at the end of each nonlinear step
  PetscErrorCode
  __libmesh_petsc_snes_monitor (SNES, PetscInt its, PetscReal fnorm, void *)
  {
    //int ierr=0;

    //if (its > 0)
      std::cout << "  NL step "
		<< std::setw(2) << its
		<< std::scientific
		<< ", |residual|_2 = " << fnorm
		<< std::endl;

    //return ierr;
    return 0;
  }

  //---------------------------------------------------------------
  // this function is called by PETSc to evaluate the residual at X
  PetscErrorCode
  __libmesh_petsc_snes_residual (SNES, Vec x, Vec r, void *ctx)
  {
    int ierr=0;

    libmesh_assert (x   != NULL);
    libmesh_assert (r   != NULL);
    libmesh_assert (ctx != NULL);

    PetscNonlinearSolver<Number>* solver =
      static_cast<PetscNonlinearSolver<Number>*> (ctx);

    NonlinearImplicitSystem &sys = solver->system();

    PetscVector<Number> X_global(x), R(r);
    PetscVector<Number>& X_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
    PetscVector<Number>& R_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.rhs);

    // Use the systems update() to get a good local version of the parallel solution
    X_global.swap(X_sys);
    R.swap(R_sys);

    sys.get_dof_map().enforce_constraints_exactly(sys);

    sys.update();

    //Swap back
    X_global.swap(X_sys);
    R.swap(R_sys);

    R.zero();

    if      (solver->residual != NULL) solver->residual (*sys.current_local_solution.get(), R);
    else if (solver->matvec   != NULL) solver->matvec   (*sys.current_local_solution.get(), &R, NULL);
    else libmesh_error();

    R.close();
    X_global.close();

    return ierr;
  }

  //---------------------------------------------------------------
  // this function is called by PETSc to evaluate the Jacobian at X
  PetscErrorCode
  __libmesh_petsc_snes_jacobian (SNES, Vec x, Mat *jac, Mat *pc, MatStructure *msflag, void *ctx)
  {
    int ierr=0;

    libmesh_assert (ctx != NULL);

    PetscNonlinearSolver<Number>* solver =
      static_cast<PetscNonlinearSolver<Number>*> (ctx);

    NonlinearImplicitSystem &sys = solver->system();

    PetscMatrix<Number> PC(*pc);
    PetscMatrix<Number> Jac(*jac);
    PetscVector<Number> X_global(x);
    PetscVector<Number>& X_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
    PetscMatrix<Number>& Jac_sys = *libmesh_cast_ptr<PetscMatrix<Number>*>(sys.matrix);

    // Use the systems update() to get a good local version of the parallel solution
    X_global.swap(X_sys);
    Jac.swap(Jac_sys);

    sys.get_dof_map().enforce_constraints_exactly(sys);
    sys.update();

    X_global.swap(X_sys);
    Jac.swap(Jac_sys);

    PC.zero();

    if      (solver->jacobian != NULL) solver->jacobian (*sys.current_local_solution.get(), PC);
    else if (solver->matvec   != NULL) solver->matvec   (*sys.current_local_solution.get(), NULL, &PC);
    else libmesh_error();

    PC.close();
    Jac.close();
    X_global.close();

    *msflag = SAME_NONZERO_PATTERN;

    return ierr;
  }

} // end extern "C"
//---------------------------------------------------------------------

//---------------------------------------------------------------------
// PetscNonlinearSolver<> methods
template <typename T>
void PetscNonlinearSolver<T>::clear ()
{
  if (this->initialized())
    {
      this->_is_initialized = false;

      int ierr=0;

      ierr = SNESDestroy(_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }
}

template <typename T>
void PetscNonlinearSolver<T>::init ()
{
  // Initialize the data structures if not done so already.
  if (!this->initialized())
    {
      this->_is_initialized = true;

      int ierr=0;

#if PETSC_VERSION_LESS_THAN(2,1,2)
      // At least until Petsc 2.1.1, the SNESCreate had a different calling syntax.
      // The second argument was of type SNESProblemType, and could have a value of
      // either SNES_NONLINEAR_EQUATIONS or SNES_UNCONSTRAINED_MINIMIZATION.
      ierr = SNESCreate(libMesh::COMM_WORLD, SNES_NONLINEAR_EQUATIONS, &_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

#else

      ierr = SNESCreate(libMesh::COMM_WORLD,&_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

#endif

#if PETSC_VERSION_LESS_THAN(2,3,3)
      ierr = SNESSetMonitor (_snes, __libmesh_petsc_snes_monitor,
			     this, PETSC_NULL);
#else
      // API name change in PETSc 2.3.3
      ierr = SNESMonitorSet (_snes, __libmesh_petsc_snes_monitor,
			     this, PETSC_NULL);
#endif
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

      ierr = SNESSetFromOptions(_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

      if(this->_preconditioner)
      {
        KSP ksp;
        ierr = SNESGetKSP (_snes, &ksp);
               CHKERRABORT(libMesh::COMM_WORLD,ierr);
        PC pc;
        ierr = KSPGetPC(ksp,&pc);
               CHKERRABORT(libMesh::COMM_WORLD,ierr);

        PCSetType(pc, PCSHELL);
        PCShellSetContext(pc,(void*)this->_preconditioner);

        //Re-Use the shell functions from petsc_linear_solver
        PCShellSetSetUp(pc,__libmesh_petsc_preconditioner_setup);
        PCShellSetApply(pc,__libmesh_petsc_preconditioner_apply);
      }
    }
}

template <typename T>
std::pair<unsigned int, Real>
PetscNonlinearSolver<T>::solve (SparseMatrix<T>&  jac_in,  // System Jacobian Matrix
				NumericVector<T>& x_in,    // Solution vector
				NumericVector<T>& r_in,    // Residual vector
				const double,              // Stopping tolerance
				const unsigned int)
{
  this->init ();

  // Make sure the data passed in are really of Petsc types
  PetscMatrix<T>* jac = libmesh_cast_ptr<PetscMatrix<T>*>(&jac_in);
  PetscVector<T>* x   = libmesh_cast_ptr<PetscVector<T>*>(&x_in);
  PetscVector<T>* r   = libmesh_cast_ptr<PetscVector<T>*>(&r_in);

  int ierr=0;
  int n_iterations =0;

  ierr = SNESSetFunction (_snes, r->vec(), __libmesh_petsc_snes_residual, this);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = SNESSetJacobian (_snes, jac->mat(), jac->mat(), __libmesh_petsc_snes_jacobian, this);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

   // Have the Krylov subspace method use our good initial guess rather than 0
   KSP ksp;
   ierr = SNESGetKSP (_snes, &ksp);
          CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Set the tolerances for the iterative solver.  Use the user-supplied
  // tolerance for the relative residual & leave the others at default values
  ierr = KSPSetTolerances (ksp, this->initial_linear_tolerance, PETSC_DEFAULT,
                           PETSC_DEFAULT, this->max_linear_iterations);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Set the tolerances for the non-linear solver.
  ierr = SNESSetTolerances(_snes, this->absolute_residual_tolerance, this->relative_residual_tolerance,
                           this->absolute_step_tolerance, this->max_nonlinear_iterations, this->max_function_evaluations);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  //Pull in command-line options
  KSPSetFromOptions(ksp);
  SNESSetFromOptions(_snes);

  //Set the preconditioning matrix
  if(this->_preconditioner)
    this->_preconditioner->set_matrix(jac_in);

//    ierr = KSPSetInitialGuessNonzero (ksp, PETSC_TRUE);
//           CHKERRABORT(libMesh::COMM_WORLD,ierr);

// Older versions (at least up to 2.1.5) of SNESSolve took 3 arguments,
// the last one being a pointer to an int to hold the number of iterations required.
# if PETSC_VERSION_LESS_THAN(2,2,0)

 ierr = SNESSolve (_snes, x->vec(), &n_iterations);
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

// 2.2.x style
#elif PETSC_VERSION_LESS_THAN(2,3,0)

 ierr = SNESSolve (_snes, x->vec());
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

// 2.3.x & newer style
#else

 ierr = SNESSolve (_snes, PETSC_NULL, x->vec());
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

#endif

  SNESConvergedReason reason;
  SNESGetConvergedReason(_snes,&reason);

  //Based on Petsc 2.3.3 documentation all diverged reasons are negative
  this->converged = reason >= 0;

  this->clear();

  // return the # of its. and the final residual norm.  Note that
  // n_iterations may be zero for PETSc versions 2.2.x and greater.
  return std::make_pair(n_iterations, 0.);
}

//------------------------------------------------------------------
// Explicit instantiations
template class PetscNonlinearSolver<Number>;

#endif // #ifdef LIBMESH_HAVE_PETSC
<|endoftext|>


<commit_before>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "jnc_io_File.h"
#include "jnc_io_IoLib.h"

namespace jnc {
namespace io {

//..............................................................................

JNC_DEFINE_OPAQUE_CLASS_TYPE(
	File,
	"io.File",
	g_ioLibGuid,
	IoLibCacheSlot_File,
	File,
	NULL
	)

JNC_BEGIN_TYPE_FUNCTION_MAP(File)
	JNC_MAP_CONSTRUCTOR(&jnc::construct<File>)
	JNC_MAP_DESTRUCTOR(&jnc::destruct<File>)
	JNC_MAP_CONST_PROPERTY("m_kind", &File::getKind)
	JNC_MAP_CONST_PROPERTY("m_size", &File::getSize)
	JNC_MAP_PROPERTY("m_position", &File::getPosition, &File::setPosition)
	JNC_MAP_FUNCTION("open",  &File::open)
	JNC_MAP_FUNCTION("close", &File::close)
	JNC_MAP_FUNCTION("setSize", &File::setSize)
	JNC_MAP_FUNCTION("read",  &File::read)
	JNC_MAP_FUNCTION("write", &File::write)
	JNC_MAP_FUNCTION("flush", &File::flush)
JNC_END_TYPE_FUNCTION_MAP()

//..............................................................................

FileKind
getFileKind(const axl::io::File& file)
{
	if (!file.isOpen())
		return FileKind_Unknown;

#if (_JNC_OS_WIN)
	static FileKind fileKindTable[] =
	{
		FileKind_Unknown, // FILE_TYPE_UNKNOWN   (0x0000)
		FileKind_Disk,    // FILE_TYPE_DISK      (0x0001)
		FileKind_Unknown, // FILE_TYPE_CHAR      (0x0002)
		FileKind_Unknown, // FILE_TYPE_PIPE      (0x0003)
	};

	dword_t type = file.m_file.getType();
	return type < countof(fileKindTable) ? fileKindTable[type] : FileKind_Unknown;
#else
	struct stat st;
	int result = ::fstat(file.m_file, &st);

	return
		result == -1 ? FileKind_Unknown :
		S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode) ? FileKind_Pipe :
		S_ISCHR(st.st_mode) ? FileKind_Serial :
		S_ISREG(st.st_mode) ? FileKind_Disk :
		FileKind_Unknown;
#endif
}

//..............................................................................

bool
JNC_CDECL
File::open(
	DataPtr namePtr,
	uint_t flags
	)
{
	close();

	bool result = m_file.open((const char*) namePtr.m_p, flags);
	if (!result)
		return false;

	m_isOpen = true;
	return true;
}

void
JNC_CDECL
File::close()
{
	m_file.close();
	m_isOpen = false;
}

//..............................................................................

} // namespace io
} // namespace jnc
<commit_msg>[jnc_io_base] typo fix: implementation of getFileKind for windows didn't detect serial ports or pipes<commit_after>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "jnc_io_File.h"
#include "jnc_io_IoLib.h"

namespace jnc {
namespace io {

//..............................................................................

JNC_DEFINE_OPAQUE_CLASS_TYPE(
	File,
	"io.File",
	g_ioLibGuid,
	IoLibCacheSlot_File,
	File,
	NULL
	)

JNC_BEGIN_TYPE_FUNCTION_MAP(File)
	JNC_MAP_CONSTRUCTOR(&jnc::construct<File>)
	JNC_MAP_DESTRUCTOR(&jnc::destruct<File>)
	JNC_MAP_CONST_PROPERTY("m_kind", &File::getKind)
	JNC_MAP_CONST_PROPERTY("m_size", &File::getSize)
	JNC_MAP_PROPERTY("m_position", &File::getPosition, &File::setPosition)
	JNC_MAP_FUNCTION("open",  &File::open)
	JNC_MAP_FUNCTION("close", &File::close)
	JNC_MAP_FUNCTION("setSize", &File::setSize)
	JNC_MAP_FUNCTION("read",  &File::read)
	JNC_MAP_FUNCTION("write", &File::write)
	JNC_MAP_FUNCTION("flush", &File::flush)
JNC_END_TYPE_FUNCTION_MAP()

//..............................................................................

FileKind
getFileKind(const axl::io::File& file)
{
	if (!file.isOpen())
		return FileKind_Unknown;

#if (_JNC_OS_WIN)
	static FileKind fileKindTable[] =
	{
		FileKind_Unknown, // FILE_TYPE_UNKNOWN   (0x0000)
		FileKind_Disk,    // FILE_TYPE_DISK      (0x0001)
		FileKind_Serial,  // FILE_TYPE_CHAR      (0x0002)
		FileKind_Pipe,    // FILE_TYPE_PIPE      (0x0003)
	};

	dword_t type = file.m_file.getType();
	return type < countof(fileKindTable) ? fileKindTable[type] : FileKind_Unknown;
#else
	struct stat st;
	int result = ::fstat(file.m_file, &st);

	return
		result == -1 ? FileKind_Unknown :
		S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode) ? FileKind_Pipe :
		S_ISCHR(st.st_mode) ? FileKind_Serial :
		S_ISREG(st.st_mode) ? FileKind_Disk :
		FileKind_Unknown;
#endif
}

//..............................................................................

bool
JNC_CDECL
File::open(
	DataPtr namePtr,
	uint_t flags
	)
{
	close();

	bool result = m_file.open((const char*) namePtr.m_p, flags);
	if (!result)
		return false;

	m_isOpen = true;
	return true;
}

void
JNC_CDECL
File::close()
{
	m_file.close();
	m_isOpen = false;
}

//..............................................................................

} // namespace io
} // namespace jnc
<|endoftext|>


<commit_before>#ifndef WIN32

#include "native.h"
#include "generic.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <curses.h>
#include <term.h>

/*
 * Marks the given result as failed, using the current value of errno
 */
void mark_failed_with_errno(JNIEnv *env, const char* message, jobject result) {
    mark_failed_with_code(env, message, errno, result);
}

/*
 * File functions
 */

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixFileFunctions_chmod(JNIEnv *env, jclass target, jstring path, jint mode, jobject result) {
    const char* pathUtf8 = env->GetStringUTFChars(path, NULL);
    int retval = chmod(pathUtf8, mode);
    env->ReleaseStringUTFChars(path, pathUtf8);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not chmod file", result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixFileFunctions_stat(JNIEnv *env, jclass target, jstring path, jobject dest, jobject result) {
    struct stat fileInfo;
    const char* pathUtf8 = env->GetStringUTFChars(path, NULL);
    int retval = stat(pathUtf8, &fileInfo);
    env->ReleaseStringUTFChars(path, pathUtf8);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not stat file", result);
        return;
    }
    jclass destClass = env->GetObjectClass(dest);
    jfieldID modeField = env->GetFieldID(destClass, "mode", "I");
    env->SetIntField(dest, modeField, 0777 & fileInfo.st_mode);
}

/*
 * Process functions
 */

JNIEXPORT jint JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_getPid(JNIEnv *env, jclass target) {
    return getpid();
}

/*
 * Terminal functions
 */

JNIEXPORT jboolean JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixTerminalFunctions_isatty(JNIEnv *env, jclass target, jint output) {
    switch (output) {
    case 0:
    case 1:
        return isatty(output+1) ? JNI_TRUE : JNI_FALSE;
    default:
        return JNI_FALSE;
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixTerminalFunctions_getTerminalSize(JNIEnv *env, jclass target, jint output, jobject dimension, jobject result) {
    struct winsize screen_size;
    int retval = ioctl(output+1, TIOCGWINSZ, &screen_size);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not fetch terminal size", result);
        return;
    }
    jclass dimensionClass = env->GetObjectClass(dimension);
    jfieldID widthField = env->GetFieldID(dimensionClass, "cols", "I");
    env->SetIntField(dimension, widthField, screen_size.ws_col);
    jfieldID heightField = env->GetFieldID(dimensionClass, "rows", "I");
    env->SetIntField(dimension, heightField, screen_size.ws_row);
}

/*
 * Terminfo functions
 */

#define NORMAL_TEXT 0
#define BRIGHT_TEXT 1
#define FOREGROUND_COLOR 2
#define CURSOR_UP 3
#define CURSOR_DOWN 4
#define CURSOR_LEFT 5
#define CURSOR_RIGHT 6
#define CURSOR_START_LINE 7
#define CLEAR_END_OF_LINE 8

#ifdef SOLARIS
#define TERMINAL_CHAR_TYPE char
#else
#define TERMINAL_CHAR_TYPE int
#endif

int current_terminal = -1;
const char* terminal_capabilities[9];

int write_to_terminal(TERMINAL_CHAR_TYPE ch) {
    write(current_terminal, &ch, 1);
}

const char* getcap(const char* capability) {
    char* cap = tgetstr((char*)capability, NULL);
//    if (cap == NULL) {
//        printf("unknown capability '%s'\n", capability);
//    }
    return cap;
}

void write_capability(JNIEnv *env, const char* capability, jobject result) {
    if (capability == NULL) {
        mark_failed_with_message(env, "unknown terminal capability", result);
        return;
    }
    if (tputs(capability, 1, write_to_terminal) == ERR) {
        mark_failed_with_message(env, "could not write to terminal", result);
        return;
    }
}

void write_param_capability(JNIEnv *env, const char* capability, int count, jobject result) {
    if (capability == NULL) {
        mark_failed_with_message(env, "unknown terminal capability", result);
        return;
    }

    capability = tparm((char*)capability, count, 0, 0, 0, 0, 0, 0, 0, 0);
    if (capability == NULL) {
        mark_failed_with_message(env, "could not format terminal capability string", result);
        return;
    }

    if (tputs(capability, 1, write_to_terminal) == ERR) {
        mark_failed_with_message(env, "could not write to terminal", result);
        return;
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_initTerminal(JNIEnv *env, jclass target, jint output, jobject result) {
    if (!isatty(output+1)) {
        mark_failed_with_message(env, "not a terminal", result);
        return;
    }
    if (current_terminal < 0) {
        char* termType = getenv("TERM");
        if (termType == NULL) {
            mark_failed_with_message(env, "$TERM not set", result);
            return;
        }
        int retval = tgetent(NULL, termType);
        if (retval != 1) {
            mark_failed_with_message(env, "could not get termcap entry", result);
            return;
        }
        terminal_capabilities[NORMAL_TEXT] = getcap("me");
        terminal_capabilities[BRIGHT_TEXT] = getcap("md");
        terminal_capabilities[FOREGROUND_COLOR] = getcap("AF");
        terminal_capabilities[CURSOR_UP] = getcap("up");
        terminal_capabilities[CURSOR_DOWN] = getcap("do");
        terminal_capabilities[CURSOR_LEFT] = getcap("le");
        terminal_capabilities[CURSOR_RIGHT] = getcap("nd");
        terminal_capabilities[CURSOR_START_LINE] = getcap("cr");
        terminal_capabilities[CLEAR_END_OF_LINE] = getcap("ce");
    }
    current_terminal = output + 1;
    write_capability(env, terminal_capabilities[NORMAL_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_bold(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[BRIGHT_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_reset(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[NORMAL_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_foreground(JNIEnv *env, jclass target, jint color, jobject result) {
    write_param_capability(env, terminal_capabilities[FOREGROUND_COLOR], color, result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_up(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_UP], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_down(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_DOWN], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_left(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_LEFT], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_right(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_RIGHT], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_startLine(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[CURSOR_START_LINE], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_clearToEndOfLine(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[CLEAR_END_OF_LINE], result);
}

#endif
<commit_msg>fixes for Solaris<commit_after>#ifndef WIN32

#include "native.h"
#include "generic.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <curses.h>
#include <term.h>

/*
 * Marks the given result as failed, using the current value of errno
 */
void mark_failed_with_errno(JNIEnv *env, const char* message, jobject result) {
    mark_failed_with_code(env, message, errno, result);
}

/*
 * File functions
 */

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixFileFunctions_chmod(JNIEnv *env, jclass target, jstring path, jint mode, jobject result) {
    const char* pathUtf8 = env->GetStringUTFChars(path, NULL);
    int retval = chmod(pathUtf8, mode);
    env->ReleaseStringUTFChars(path, pathUtf8);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not chmod file", result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixFileFunctions_stat(JNIEnv *env, jclass target, jstring path, jobject dest, jobject result) {
    struct stat fileInfo;
    const char* pathUtf8 = env->GetStringUTFChars(path, NULL);
    int retval = stat(pathUtf8, &fileInfo);
    env->ReleaseStringUTFChars(path, pathUtf8);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not stat file", result);
        return;
    }
    jclass destClass = env->GetObjectClass(dest);
    jfieldID modeField = env->GetFieldID(destClass, "mode", "I");
    env->SetIntField(dest, modeField, 0777 & fileInfo.st_mode);
}

/*
 * Process functions
 */

JNIEXPORT jint JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_getPid(JNIEnv *env, jclass target) {
    return getpid();
}

/*
 * Terminal functions
 */

JNIEXPORT jboolean JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixTerminalFunctions_isatty(JNIEnv *env, jclass target, jint output) {
    switch (output) {
    case 0:
    case 1:
        return isatty(output+1) ? JNI_TRUE : JNI_FALSE;
    default:
        return JNI_FALSE;
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixTerminalFunctions_getTerminalSize(JNIEnv *env, jclass target, jint output, jobject dimension, jobject result) {
    struct winsize screen_size;
    int retval = ioctl(output+1, TIOCGWINSZ, &screen_size);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not fetch terminal size", result);
        return;
    }
    jclass dimensionClass = env->GetObjectClass(dimension);
    jfieldID widthField = env->GetFieldID(dimensionClass, "cols", "I");
    env->SetIntField(dimension, widthField, screen_size.ws_col);
    jfieldID heightField = env->GetFieldID(dimensionClass, "rows", "I");
    env->SetIntField(dimension, heightField, screen_size.ws_row);
}

/*
 * Terminfo functions
 */

#define NORMAL_TEXT 0
#define BRIGHT_TEXT 1
#define FOREGROUND_COLOR 2
#define CURSOR_UP 3
#define CURSOR_DOWN 4
#define CURSOR_LEFT 5
#define CURSOR_RIGHT 6
#define CURSOR_START_LINE 7
#define CLEAR_END_OF_LINE 8

#ifdef SOLARIS
#define TERMINAL_CHAR_TYPE char
#else
#define TERMINAL_CHAR_TYPE int
#endif

int current_terminal = -1;
const char* terminal_capabilities[9];

int write_to_terminal(TERMINAL_CHAR_TYPE ch) {
    write(current_terminal, &ch, 1);
}

const char* getcap(const char* capability) {
    char* cap = tgetstr((char*)capability, NULL);
    if (cap == NULL) {
        printf("unknown capability '%s'\n", capability);
    }
    return cap;
}

void write_capability(JNIEnv *env, const char* capability, jobject result) {
    if (capability == NULL) {
        mark_failed_with_message(env, "unknown terminal capability", result);
        return;
    }
    if (tputs((char*)capability, 1, write_to_terminal) == ERR) {
        mark_failed_with_message(env, "could not write to terminal", result);
        return;
    }
}

void write_param_capability(JNIEnv *env, const char* capability, int count, jobject result) {
    if (capability == NULL) {
        mark_failed_with_message(env, "unknown terminal capability", result);
        return;
    }

    capability = tparm((char*)capability, count, 0, 0, 0, 0, 0, 0, 0, 0);
    if (capability == NULL) {
        mark_failed_with_message(env, "could not format terminal capability string", result);
        return;
    }

    if (tputs((char*)capability, 1, write_to_terminal) == ERR) {
        mark_failed_with_message(env, "could not write to terminal", result);
        return;
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_initTerminal(JNIEnv *env, jclass target, jint output, jobject result) {
    if (!isatty(output+1)) {
        mark_failed_with_message(env, "not a terminal", result);
        return;
    }
    if (current_terminal < 0) {
        char* termType = getenv("TERM");
        if (termType == NULL) {
            mark_failed_with_message(env, "$TERM not set", result);
            return;
        }
        int retval = tgetent(NULL, termType);
        if (retval != 1) {
            mark_failed_with_message(env, "could not get termcap entry", result);
            return;
        }
        terminal_capabilities[NORMAL_TEXT] = getcap("me");
        terminal_capabilities[BRIGHT_TEXT] = getcap("md");
        terminal_capabilities[FOREGROUND_COLOR] = getcap("AF");
        terminal_capabilities[CURSOR_UP] = getcap("up");
        terminal_capabilities[CURSOR_DOWN] = getcap("do");
        terminal_capabilities[CURSOR_LEFT] = getcap("le");
        terminal_capabilities[CURSOR_RIGHT] = getcap("nd");
        terminal_capabilities[CURSOR_START_LINE] = getcap("cr");
        terminal_capabilities[CLEAR_END_OF_LINE] = getcap("ce");
    }
    current_terminal = output + 1;
    write_capability(env, terminal_capabilities[NORMAL_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_bold(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[BRIGHT_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_reset(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[NORMAL_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_foreground(JNIEnv *env, jclass target, jint color, jobject result) {
    write_param_capability(env, terminal_capabilities[FOREGROUND_COLOR], color, result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_up(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_UP], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_down(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_DOWN], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_left(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_LEFT], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_right(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_RIGHT], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_startLine(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[CURSOR_START_LINE], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_clearToEndOfLine(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[CLEAR_END_OF_LINE], result);
}

#endif
<|endoftext|>


<commit_before><commit_msg>Fix bug in Pac02 implementation<commit_after><|endoftext|>


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

This file is part of the QtMediaHub project on http://www.gitorious.org.

Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
All rights reserved.

Contact:  Nokia Corporation (qt-info@nokia.com)**

You may use this file under the terms of the BSD license as follows:

"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 of conditions 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 materials provided with the distribution.
* Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
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 OWNER 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 "playlist.h"
#include "media.h"
#include "global.h"

#include <QList>
#include <QMetaEnum>
#include <QModelIndex>

#define DEBUG if (0) qDebug() << __PRETTY_FUNCTION__

Playlist::Playlist(QObject *parent)
    : QAbstractListModel(parent)
    , m_playMode(Normal)
{
    QHash<int, QByteArray> roleNames = QAbstractListModel::roleNames();
    roleNames.unite(Media::roleNames());
    setRoleNames(roleNames);
}

Playlist::~Playlist()
{
}

QVariant Playlist::data(const QModelIndex &index, int role) const
{
    QVariant rv;

    if (!index.isValid())
        return rv;

    if (0 <= index.row() && index.row() < content.size()) {
        const PlaylistItem &info = content.at(index.row());
        if (role == Qt::DisplayRole) {
            return info.name;
        } else if (role == Media::PreviewUrlRole) {
            return info.previewUrl;
        } else if (role == Media::FilePathRole) {
            return info.filePath;
        } else if (role == Media::ModelIndexRole) {
            return qVariantFromValue(index);
        }
    }

    return rv;
}

int Playlist::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return content.count();
}

QVariant Playlist::add(const QModelIndex &index, PlaylistRoles role, DepthRoles depth)
{
    if (!index.isValid()) {
        DEBUG << "index is not valid, epic fail";
        return QVariant(); // we don't have a model() to work with
    }

    if (role == Playlist::Replace && rowCount() > 0) {
        beginRemoveRows(QModelIndex(), 0, rowCount()-1);
        content.clear();
        endRemoveRows();
    }

    // check if already in playlist
    int pos = -1;
    for (int i = 0; i < content.count(); ++i) {
        if (content.at(i).filePath == index.data(Media::FilePathRole).toString()) {
            pos = i;
            break;
        }
    }

    if (pos == -1) {
        if (depth == Playlist::Flat) {
            // ## this needs to support fetchmore?
            QModelIndex parent = index.parent();
            for (int i = 0; i < index.model()->rowCount(parent); i++)
                appendItem(parent.child(i, 0));
        }
        pos = index.row(); // ## incorrect if it's invalid
    }

    DEBUG << "Playlist now has " << rowCount() << " items";

    return qVariantFromValue(createIndex(pos, 0));
}

QModelIndex Playlist::index(int row) const
{
    return createIndex(row, 0);
}

QModelIndex Playlist::playNextIndex(const QModelIndex &idx) const
{
    QModelIndex next;

    if (m_playMode == Shuffle) {
        next = index(int((qreal(qrand())/RAND_MAX)*rowCount()));
    } else {
        if (idx.row() >= rowCount()-1)
            next = index(0);
        else
            next = index(idx.row()+1);
    }

    return next;
}

QModelIndex Playlist::playPreviousIndex(const QModelIndex &idx) const
{
    QModelIndex prev;

    if (idx.row() <= 0)
        prev = index(rowCount()-1);
    else
        prev = index(idx.row()-1);

    return prev;
}

void Playlist::setPlayMode(Playlist::PlayModeRoles mode)
{
    if (m_playMode != mode) {
        m_playMode = mode;
        emit playModeChanged();
    }
}

void Playlist::appendItem(const QModelIndex  &index)
{
    int start = rowCount()-1 < 0 ? 0 : rowCount()-1;
    int end = rowCount() < 0 ? 1 : rowCount();

    emit beginInsertRows(QModelIndex(), start, end);
    PlaylistItem item;
    item.name = index.data(Qt::DisplayRole).toString();
    item.filePath = index.data(Media::FilePathRole).toString();
    item.previewUrl = index.data(Media::PreviewUrlRole).toString();
    content.append(item);
    emit endInsertRows();
}

<commit_msg>Since index is valid, checking the row's range is unnecessary<commit_after>/****************************************************************************

This file is part of the QtMediaHub project on http://www.gitorious.org.

Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
All rights reserved.

Contact:  Nokia Corporation (qt-info@nokia.com)**

You may use this file under the terms of the BSD license as follows:

"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 of conditions 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 materials provided with the distribution.
* Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
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 OWNER 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 "playlist.h"
#include "media.h"
#include "global.h"

#include <QList>
#include <QMetaEnum>
#include <QModelIndex>

#define DEBUG if (0) qDebug() << __PRETTY_FUNCTION__

Playlist::Playlist(QObject *parent)
    : QAbstractListModel(parent)
    , m_playMode(Normal)
{
    QHash<int, QByteArray> roleNames = QAbstractListModel::roleNames();
    roleNames.unite(Media::roleNames());
    setRoleNames(roleNames);
}

Playlist::~Playlist()
{
}

QVariant Playlist::data(const QModelIndex &index, int role) const
{
    QVariant rv;

    if (!index.isValid())
        return rv;

    const PlaylistItem &info = content.at(index.row());
    if (role == Qt::DisplayRole) {
        return info.name;
    } else if (role == Media::PreviewUrlRole) {
        return info.previewUrl;
    } else if (role == Media::FilePathRole) {
        return info.filePath;
    } else if (role == Media::ModelIndexRole) {
        return qVariantFromValue(index);
    }

    return rv;
}

int Playlist::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return content.count();
}

QVariant Playlist::add(const QModelIndex &index, PlaylistRoles role, DepthRoles depth)
{
    if (!index.isValid()) {
        DEBUG << "index is not valid, epic fail";
        return QVariant(); // we don't have a model() to work with
    }

    if (role == Playlist::Replace && rowCount() > 0) {
        beginRemoveRows(QModelIndex(), 0, rowCount()-1);
        content.clear();
        endRemoveRows();
    }

    // check if already in playlist
    int pos = -1;
    for (int i = 0; i < content.count(); ++i) {
        if (content.at(i).filePath == index.data(Media::FilePathRole).toString()) {
            pos = i;
            break;
        }
    }

    if (pos == -1) {
        if (depth == Playlist::Flat) {
            // ## this needs to support fetchmore?
            QModelIndex parent = index.parent();
            for (int i = 0; i < index.model()->rowCount(parent); i++)
                appendItem(parent.child(i, 0));
        }
        pos = index.row(); // ## incorrect if it's invalid
    }

    DEBUG << "Playlist now has " << rowCount() << " items";

    return qVariantFromValue(createIndex(pos, 0));
}

QModelIndex Playlist::index(int row) const
{
    return createIndex(row, 0);
}

QModelIndex Playlist::playNextIndex(const QModelIndex &idx) const
{
    QModelIndex next;

    if (m_playMode == Shuffle) {
        next = index(int((qreal(qrand())/RAND_MAX)*rowCount()));
    } else {
        if (idx.row() >= rowCount()-1)
            next = index(0);
        else
            next = index(idx.row()+1);
    }

    return next;
}

QModelIndex Playlist::playPreviousIndex(const QModelIndex &idx) const
{
    QModelIndex prev;

    if (idx.row() <= 0)
        prev = index(rowCount()-1);
    else
        prev = index(idx.row()-1);

    return prev;
}

void Playlist::setPlayMode(Playlist::PlayModeRoles mode)
{
    if (m_playMode != mode) {
        m_playMode = mode;
        emit playModeChanged();
    }
}

void Playlist::appendItem(const QModelIndex  &index)
{
    int start = rowCount()-1 < 0 ? 0 : rowCount()-1;
    int end = rowCount() < 0 ? 1 : rowCount();

    emit beginInsertRows(QModelIndex(), start, end);
    PlaylistItem item;
    item.name = index.data(Qt::DisplayRole).toString();
    item.filePath = index.data(Media::FilePathRole).toString();
    item.previewUrl = index.data(Media::PreviewUrlRole).toString();
    content.append(item);
    emit endInsertRows();
}

<|endoftext|>