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

Daemon GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.

This file is part of the Daemon GPL Source Code (Daemon Source Code).

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

Daemon Source Code 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 General Public License for more details.

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

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

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

// this is only used for visualization tools in cm_ debug functions

#include "cm_local.h"

// counters are only bumped when running single threaded,
// because they are an awefull coherence problem
int c_active_windings;
int c_peak_windings;
int c_winding_allocs;
int c_winding_points;

/*
=============
AllocWinding
=============
*/
winding_t      *AllocWinding( int points )
{
	winding_t *w;
	int       s;

	c_winding_allocs++;
	c_winding_points += points;
	c_active_windings++;

	if ( c_active_windings > c_peak_windings )
	{
		c_peak_windings = c_active_windings;
	}

	s = sizeof( vec_t ) * 3 * points + sizeof( int );
	w = ( winding_t * ) Z_Malloc( s );
	memset( w, 0, s );
	return w;
}

void FreeWinding( winding_t *w )
{
	if ( * ( unsigned * ) w == 0xdeaddead )
	{
		Sys::Error( "FreeWinding: freed a freed winding" );
	}

	* ( unsigned * ) w = 0xdeaddead;

	c_active_windings--;
	Z_Free( w );
}

void WindingBounds( winding_t *w, vec3_t mins, vec3_t maxs )
{
	vec_t v;
	int   i, j;

	mins[ 0 ] = mins[ 1 ] = mins[ 2 ] = MAX_MAP_BOUNDS;
	maxs[ 0 ] = maxs[ 1 ] = maxs[ 2 ] = -MAX_MAP_BOUNDS;

	for ( i = 0; i < w->numpoints; i++ )
	{
		for ( j = 0; j < 3; j++ )
		{
			v = w->p[ i ][ j ];

			if ( v < mins[ j ] )
			{
				mins[ j ] = v;
			}

			if ( v > maxs[ j ] )
			{
				maxs[ j ] = v;
			}
		}
	}
}

/*
=================
BaseWindingForPlane
=================
*/
winding_t      *BaseWindingForPlane( vec3_t normal, vec_t dist )
{
	int       i, x;
	vec_t     max, v;
	vec3_t    org, vright, vup;
	winding_t *w;

// find the major axis

	max = -MAX_MAP_BOUNDS;
	x = -1;

	for ( i = 0; i < 3; i++ )
	{
		v = Q_fabs( normal[ i ] );

		if ( v > max )
		{
			x = i;
			max = v;
		}
	}

	if ( x == -1 )
	{
		Sys::Drop( "BaseWindingForPlane: no axis found" );
	}

	VectorCopy( vec3_origin, vup );

	switch ( x )
	{
		case 0:
		case 1:
			vup[ 2 ] = 1;
			break;

		case 2:
			vup[ 0 ] = 1;
			break;
	}

	v = DotProduct( vup, normal );
	VectorMA( vup, -v, normal, vup );
	VectorNormalize2( vup, vup );

	VectorScale( normal, dist, org );

	CrossProduct( vup, normal, vright );

	VectorScale( vup, MAX_MAP_BOUNDS, vup );
	VectorScale( vright, MAX_MAP_BOUNDS, vright );

// project a really big axis aligned box onto the plane
	w = AllocWinding( 4 );

	VectorSubtract( org, vright, w->p[ 0 ] );
	VectorAdd( w->p[ 0 ], vup, w->p[ 0 ] );

	VectorAdd( org, vright, w->p[ 1 ] );
	VectorAdd( w->p[ 1 ], vup, w->p[ 1 ] );

	VectorAdd( org, vright, w->p[ 2 ] );
	VectorSubtract( w->p[ 2 ], vup, w->p[ 2 ] );

	VectorSubtract( org, vright, w->p[ 3 ] );
	VectorSubtract( w->p[ 3 ], vup, w->p[ 3 ] );

	w->numpoints = 4;

	return w;
}

/*
==================
CopyWinding
==================
*/
winding_t      *CopyWinding( winding_t *w )
{
	intptr_t  size;
	winding_t *c;

	c = AllocWinding( w->numpoints );
	size = ( intptr_t )( ( winding_t * ) nullptr )->p[ w->numpoints ];
	memcpy( c, w, size );
	return c;
}

/*
=============
ChopWindingInPlace
=============
*/
void ChopWindingInPlace( winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon )
{
// FIXME: https://github.com/DaemonEngine/Daemon/issues/169
// This is required to load oasis (Wolf:ET) and  moteof (Q3) maps.
// Maps requiring this workaround are usually large and detailed maps
// but some very large maps do not require such workaround.
#define WORKAROUND_MAX_POINTS_ON_WINDING 4 * MAX_POINTS_ON_WINDING
	winding_t    *in;
	vec_t        dists[ WORKAROUND_MAX_POINTS_ON_WINDING + 4 ];
	planeSide_t  sides[ WORKAROUND_MAX_POINTS_ON_WINDING + 4 ];
	int          counts[ 3 ];
	static vec_t dot; // VC 4.2 optimizer bug if not static
	int          i, j;
	vec_t        *p1, *p2;
	vec3_t       mid;
	winding_t    *f;
	int          maxpts;

	in = *inout;
	counts[ 0 ] = counts[ 1 ] = counts[ 2 ] = 0;

// determine sides for each point
	for ( i = 0; i < in->numpoints; i++ )
	{
		dot = DotProduct( in->p[ i ], normal );
		dot -= dist;
		dists[ i ] = dot;

		if ( dot > epsilon )
		{
			sides[ i ] = planeSide_t::SIDE_FRONT;
		}
		else if ( dot < -epsilon )
		{
			sides[ i ] = planeSide_t::SIDE_BACK;
		}
		else
		{
			sides[ i ] = planeSide_t::SIDE_ON;
		}

		counts[ Util::ordinal(sides[ i ]) ]++;
	}

	sides[ i ] = sides[ 0 ];
	dists[ i ] = dists[ 0 ];

	if ( !counts[ 0 ] )
	{
		FreeWinding( in );
		*inout = nullptr;
		return;
	}

	if ( !counts[ 1 ] )
	{
		return; // inout stays the same
	}

	maxpts = in->numpoints + 4; // can't use counts[0]+2 because
	// of fp grouping errors

	f = AllocWinding( maxpts );

	for ( i = 0; i < in->numpoints; i++ )
	{
		p1 = in->p[ i ];

		if ( sides[ i ] == planeSide_t::SIDE_ON )
		{
			VectorCopy( p1, f->p[ f->numpoints ] );
			f->numpoints++;
			continue;
		}

		if ( sides[ i ] == planeSide_t::SIDE_FRONT )
		{
			VectorCopy( p1, f->p[ f->numpoints ] );
			f->numpoints++;
		}

		if ( sides[ i + 1 ] == planeSide_t::SIDE_ON || sides[ i + 1 ] == sides[ i ] )
		{
			continue;
		}

		// generate a split point
		p2 = in->p[( i + 1 ) % in->numpoints ];

		dot = dists[ i ] / ( dists[ i ] - dists[ i + 1 ] );

		for ( j = 0; j < 3; j++ )
		{
			// avoid round off error when possible
			if ( normal[ j ] == 1 )
			{
				mid[ j ] = dist;
			}
			else if ( normal[ j ] == -1 )
			{
				mid[ j ] = -dist;
			}
			else
			{
				mid[ j ] = p1[ j ] + dot * ( p2[ j ] - p1[ j ] );
			}
		}

		VectorCopy( mid, f->p[ f->numpoints ] );
		f->numpoints++;
	}

	if ( f->numpoints > maxpts )
	{
		Sys::Drop( "ClipWinding: points exceeded estimate" );
	}

	if ( f->numpoints > MAX_POINTS_ON_WINDING )
	{
		Log::Debug( "ClipWinding: MAX_POINTS_ON_WINDING, %d > %d, please fix Daemon#169, applying workaround just for you", f->numpoints, MAX_POINTS_ON_WINDING );
	}

	if ( f->numpoints > WORKAROUND_MAX_POINTS_ON_WINDING )
	{
		Sys::Drop( "ClipWinding: MAX_POINTS_ON_WINDING, can't workaround more, %d > %d, maybe that's an issue on map side?", f->numpoints, WORKAROUND_MAX_POINTS_ON_WINDING );
	}

	FreeWinding( in );
	*inout = f;
}

<commit_msg>[cm] Ensure macro evaluated as expected<commit_after>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.

This file is part of the Daemon GPL Source Code (Daemon Source Code).

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

Daemon Source Code 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 General Public License for more details.

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

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

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

// this is only used for visualization tools in cm_ debug functions

#include "cm_local.h"

// counters are only bumped when running single threaded,
// because they are an awefull coherence problem
int c_active_windings;
int c_peak_windings;
int c_winding_allocs;
int c_winding_points;

/*
=============
AllocWinding
=============
*/
winding_t      *AllocWinding( int points )
{
	winding_t *w;
	int       s;

	c_winding_allocs++;
	c_winding_points += points;
	c_active_windings++;

	if ( c_active_windings > c_peak_windings )
	{
		c_peak_windings = c_active_windings;
	}

	s = sizeof( vec_t ) * 3 * points + sizeof( int );
	w = ( winding_t * ) Z_Malloc( s );
	memset( w, 0, s );
	return w;
}

void FreeWinding( winding_t *w )
{
	if ( * ( unsigned * ) w == 0xdeaddead )
	{
		Sys::Error( "FreeWinding: freed a freed winding" );
	}

	* ( unsigned * ) w = 0xdeaddead;

	c_active_windings--;
	Z_Free( w );
}

void WindingBounds( winding_t *w, vec3_t mins, vec3_t maxs )
{
	vec_t v;
	int   i, j;

	mins[ 0 ] = mins[ 1 ] = mins[ 2 ] = MAX_MAP_BOUNDS;
	maxs[ 0 ] = maxs[ 1 ] = maxs[ 2 ] = -MAX_MAP_BOUNDS;

	for ( i = 0; i < w->numpoints; i++ )
	{
		for ( j = 0; j < 3; j++ )
		{
			v = w->p[ i ][ j ];

			if ( v < mins[ j ] )
			{
				mins[ j ] = v;
			}

			if ( v > maxs[ j ] )
			{
				maxs[ j ] = v;
			}
		}
	}
}

/*
=================
BaseWindingForPlane
=================
*/
winding_t      *BaseWindingForPlane( vec3_t normal, vec_t dist )
{
	int       i, x;
	vec_t     max, v;
	vec3_t    org, vright, vup;
	winding_t *w;

// find the major axis

	max = -MAX_MAP_BOUNDS;
	x = -1;

	for ( i = 0; i < 3; i++ )
	{
		v = Q_fabs( normal[ i ] );

		if ( v > max )
		{
			x = i;
			max = v;
		}
	}

	if ( x == -1 )
	{
		Sys::Drop( "BaseWindingForPlane: no axis found" );
	}

	VectorCopy( vec3_origin, vup );

	switch ( x )
	{
		case 0:
		case 1:
			vup[ 2 ] = 1;
			break;

		case 2:
			vup[ 0 ] = 1;
			break;
	}

	v = DotProduct( vup, normal );
	VectorMA( vup, -v, normal, vup );
	VectorNormalize2( vup, vup );

	VectorScale( normal, dist, org );

	CrossProduct( vup, normal, vright );

	VectorScale( vup, MAX_MAP_BOUNDS, vup );
	VectorScale( vright, MAX_MAP_BOUNDS, vright );

// project a really big axis aligned box onto the plane
	w = AllocWinding( 4 );

	VectorSubtract( org, vright, w->p[ 0 ] );
	VectorAdd( w->p[ 0 ], vup, w->p[ 0 ] );

	VectorAdd( org, vright, w->p[ 1 ] );
	VectorAdd( w->p[ 1 ], vup, w->p[ 1 ] );

	VectorAdd( org, vright, w->p[ 2 ] );
	VectorSubtract( w->p[ 2 ], vup, w->p[ 2 ] );

	VectorSubtract( org, vright, w->p[ 3 ] );
	VectorSubtract( w->p[ 3 ], vup, w->p[ 3 ] );

	w->numpoints = 4;

	return w;
}

/*
==================
CopyWinding
==================
*/
winding_t      *CopyWinding( winding_t *w )
{
	intptr_t  size;
	winding_t *c;

	c = AllocWinding( w->numpoints );
	size = ( intptr_t )( ( winding_t * ) nullptr )->p[ w->numpoints ];
	memcpy( c, w, size );
	return c;
}

/*
=============
ChopWindingInPlace
=============
*/
void ChopWindingInPlace( winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon )
{
// FIXME: https://github.com/DaemonEngine/Daemon/issues/169
// This is required to load oasis (Wolf:ET) and  moteof (Q3) maps.
// Maps requiring this workaround are usually large and detailed maps
// but some very large maps do not require such workaround.
#define WORKAROUND_MAX_POINTS_ON_WINDING (4 * MAX_POINTS_ON_WINDING)
	winding_t    *in;
	vec_t        dists[ WORKAROUND_MAX_POINTS_ON_WINDING + 4 ];
	planeSide_t  sides[ WORKAROUND_MAX_POINTS_ON_WINDING + 4 ];
	int          counts[ 3 ];
	static vec_t dot; // VC 4.2 optimizer bug if not static
	int          i, j;
	vec_t        *p1, *p2;
	vec3_t       mid;
	winding_t    *f;
	int          maxpts;

	in = *inout;
	counts[ 0 ] = counts[ 1 ] = counts[ 2 ] = 0;

// determine sides for each point
	for ( i = 0; i < in->numpoints; i++ )
	{
		dot = DotProduct( in->p[ i ], normal );
		dot -= dist;
		dists[ i ] = dot;

		if ( dot > epsilon )
		{
			sides[ i ] = planeSide_t::SIDE_FRONT;
		}
		else if ( dot < -epsilon )
		{
			sides[ i ] = planeSide_t::SIDE_BACK;
		}
		else
		{
			sides[ i ] = planeSide_t::SIDE_ON;
		}

		counts[ Util::ordinal(sides[ i ]) ]++;
	}

	sides[ i ] = sides[ 0 ];
	dists[ i ] = dists[ 0 ];

	if ( !counts[ 0 ] )
	{
		FreeWinding( in );
		*inout = nullptr;
		return;
	}

	if ( !counts[ 1 ] )
	{
		return; // inout stays the same
	}

	maxpts = in->numpoints + 4; // can't use counts[0]+2 because
	// of fp grouping errors

	f = AllocWinding( maxpts );

	for ( i = 0; i < in->numpoints; i++ )
	{
		p1 = in->p[ i ];

		if ( sides[ i ] == planeSide_t::SIDE_ON )
		{
			VectorCopy( p1, f->p[ f->numpoints ] );
			f->numpoints++;
			continue;
		}

		if ( sides[ i ] == planeSide_t::SIDE_FRONT )
		{
			VectorCopy( p1, f->p[ f->numpoints ] );
			f->numpoints++;
		}

		if ( sides[ i + 1 ] == planeSide_t::SIDE_ON || sides[ i + 1 ] == sides[ i ] )
		{
			continue;
		}

		// generate a split point
		p2 = in->p[( i + 1 ) % in->numpoints ];

		dot = dists[ i ] / ( dists[ i ] - dists[ i + 1 ] );

		for ( j = 0; j < 3; j++ )
		{
			// avoid round off error when possible
			if ( normal[ j ] == 1 )
			{
				mid[ j ] = dist;
			}
			else if ( normal[ j ] == -1 )
			{
				mid[ j ] = -dist;
			}
			else
			{
				mid[ j ] = p1[ j ] + dot * ( p2[ j ] - p1[ j ] );
			}
		}

		VectorCopy( mid, f->p[ f->numpoints ] );
		f->numpoints++;
	}

	if ( f->numpoints > maxpts )
	{
		Sys::Drop( "ClipWinding: points exceeded estimate" );
	}

	if ( f->numpoints > MAX_POINTS_ON_WINDING )
	{
		Log::Debug( "ClipWinding: MAX_POINTS_ON_WINDING, %d > %d, please fix Daemon#169, applying workaround just for you", f->numpoints, MAX_POINTS_ON_WINDING );
	}

	if ( f->numpoints > WORKAROUND_MAX_POINTS_ON_WINDING )
	{
		Sys::Drop( "ClipWinding: MAX_POINTS_ON_WINDING, can't workaround more, %d > %d, maybe that's an issue on map side?", f->numpoints, WORKAROUND_MAX_POINTS_ON_WINDING );
	}

	FreeWinding( in );
	*inout = f;
}

<|endoftext|>


<commit_before>// Time:  O(n)
// Space: O(1)

class Solution {
    /**
     * @param A: Given an integers array A
     * @return: A long long array B and B[i]= A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1]
     */
public:
    vector<long long> productExcludeItself(vector<int> &nums) {
        if (nums.empty()) {
            return {};
        }

        vector<long long> left_product(nums.size());

        left_product[0] = 1;
        for (int i = 1; i < nums.size(); ++i) {
            left_product[i] = left_product[i - 1] * nums[i - 1];
        }

        int right_product = 1;
        for (int j = nums.size() - 2; j >= 0; --j) {
            right_product *= nums[j + 1];
            left_product[j] = left_product[j] * right_product;
        }

        return left_product;
    }
};

// Time:  O(n)
// Space: O(n)
class Solution2 {
public:
    /**
     * @param A: Given an integers array A
     * @return: A long long array B and B[i]= A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1]
     */
    vector<long long> productExcludeItself(vector<int> &nums) {
        if (nums.empty()) {
            return {};
        }

        vector<long long> left_product(nums.size());
        vector<long long> right_product(nums.size());
        vector<long long> product(nums.size());

        left_product[0] = 1;
        for (int i = 1; i < nums.size(); ++i) {
            left_product[i] = left_product[i - 1] * nums[i - 1];
        }

        right_product[nums.size() - 1] = 1;
        for (int j = nums.size() - 2; j >= 0; --j) {
            right_product[j] = right_product[j + 1] * nums[j + 1];
        }

        for (int k = 0; k < nums.size(); ++k) {
            product[k] = left_product[k] * right_product[k];
        }

        return product;
    }
};
<commit_msg>Update product-of-array-exclude-itself.cpp<commit_after>// Time:  O(n)
// Space: O(1)

class Solution {
    /**
     * @param A: Given an integers array A
     * @return: A long long array B and B[i]= A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1]
     */
public:
    vector<long long> productExcludeItself(vector<int> &nums) {
        if (nums.empty()) {
            return {};
        }

        vector<long long> left_product(nums.size());

        left_product[0] = 1;
        for (int i = 1; i < nums.size(); ++i) {
            left_product[i] = left_product[i - 1] * nums[i - 1];
        }

        int right_product = 1;
        for (int i = nums.size() - 2; i >= 0; --i) {
            right_product *= nums[i + 1];
            left_product[i] = left_product[i] * right_product;
        }

        return left_product;
    }
};

// Time:  O(n)
// Space: O(n)
class Solution2 {
public:
    /**
     * @param A: Given an integers array A
     * @return: A long long array B and B[i]= A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1]
     */
    vector<long long> productExcludeItself(vector<int> &nums) {
        if (nums.empty()) {
            return {};
        }

        vector<long long> left_product(nums.size());
        vector<long long> right_product(nums.size());
        vector<long long> product(nums.size());

        left_product[0] = 1;
        for (int i = 1; i < nums.size(); ++i) {
            left_product[i] = left_product[i - 1] * nums[i - 1];
        }

        right_product[nums.size() - 1] = 1;
        for (int j = nums.size() - 2; j >= 0; --j) {
            right_product[j] = right_product[j + 1] * nums[j + 1];
        }

        for (int k = 0; k < nums.size(); ++k) {
            product[k] = left_product[k] * right_product[k];
        }

        return product;
    }
};
<|endoftext|>


<commit_before>/**
 * @file Cosa/UML/Connector.hh
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2015, Mikael Patel
 *
 * 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.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#ifndef COSA_UML_CONNECTOR_HH
#define COSA_UML_CONNECTOR_HH

#include "Cosa/UML/Controller.hh"

namespace UML {

/**
 * The Connector class for a given type. Implements value set and
 * get. The setting of the connector value will force the scheduling
 * of capsules that are listening for value change. The template
 * parameter ON_CHANGE can be used to filter on new values. The
 * default is scheduling on any setting. By giving ON_CHANGE the value
 * true the connector will only schedule if the value setting is
 * different than the previous value.

 * @param[in] T connector value type.
 * @param[in] ON_CHANGE flag (Default false).
 *
 * @section Diagram
 * @code
 *
 *     Capsule                             Capsule
 *   +---------+                         +---------+
 *   |   c1    |                         |   c2    |
 *   |         |                         |         |
 *   |      [Port]---[Connector<T>]--->[Port]      |
 *   |         |                         |         |
 *   +---------+                         +---------+
 *
 * @endcode
 */
template<typename T, bool ON_CHANGE = false>
class Connector {
public:
  /**
   * Construct Connector with given null terminated vector of
   * listeners, and initial value.
   * @param[in] listeners null terminated vector of capsule references.
   * @param[in] value initial value of connector.
   */
  Connector(Capsule* const* listeners, T value) :
    m_value(value),
    m_listeners(listeners)
  {}

  /**
   * Set the connector with given value. Schedule listener
   * capsules.
   * @param[in] value to update with.
   * @return value.
   */
  T operator=(T value)
  {
    if (ON_CHANGE && (m_value == value)) return (value);
    m_value = value;
    controller.schedule(m_listeners);
    return (value);
  }

  /**
   * Set the connector with value from given connector. Schedule
   * listener capsules.
   * @param[in] connector value to assign.
   * @return value.
   */
  T operator=(Connector<T> &connector)
  {
    return (*this = connector.m_value);
  }

  /**
   * Get the connector value.
   * @return value.
   */
  operator T()
  {
    return (m_value);
  }

protected:
  T m_value;
  Capsule* const* m_listeners;
};

/**
 * Boolean Connector with value filtering, i.e. on value change
 * scheduling.
 */
typedef Connector<bool,true> Signal;

};
#endif
<commit_msg>Cleanup.<commit_after>/**
 * @file Cosa/UML/Connector.hh
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2015, Mikael Patel
 *
 * 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.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#ifndef COSA_UML_CONNECTOR_HH
#define COSA_UML_CONNECTOR_HH

#include "Cosa/UML/Controller.hh"

namespace UML {

/**
 * The Connector class for a given type. Implements value set and
 * get. The setting of the connector value will force the scheduling
 * of capsules that are listening for value change. The template
 * parameter ON_CHANGE can be used to filter on new values. The
 * default is scheduling on any setting. By giving ON_CHANGE the value
 * true the connector will only schedule if the value setting is
 * different than the previous value.
 * @param[in] T connector value type.
 * @param[in] ON_CHANGE flag (Default false).
 *
 * @section Diagram
 * @code
 *
 *     Capsule                             Capsule
 *   +---------+                         +---------+
 *   |   c1    |                         |   c2    |
 *   |         |                         |         |
 *   |      [Port]---[Connector<T>]--->[Port]      |
 *   |         |                         |         |
 *   +---------+                         +---------+
 *
 * @endcode
 */
template<typename T, bool ON_CHANGE = false>
class Connector {
public:
  /**
   * Construct Connector with given null terminated vector of
   * listeners, and initial value.
   * @param[in] listeners null terminated vector of capsule references.
   * @param[in] value initial value of connector.
   */
  Connector(Capsule* const* listeners, T value) :
    m_value(value),
    m_listeners(listeners)
  {}

  /**
   * Set the connector with given value. Schedule listener
   * capsules.
   * @param[in] value to update with.
   * @return value.
   */
  T operator=(T value)
  {
    if (ON_CHANGE && (m_value == value)) return (value);
    m_value = value;
    controller.schedule(m_listeners);
    return (value);
  }

  /**
   * Set the connector with value from given connector. Schedule
   * listener capsules.
   * @param[in] connector value to assign.
   * @return value.
   */
  T operator=(Connector<T> &connector)
  {
    return (*this = connector.m_value);
  }

  /**
   * Get the connector value.
   * @return value.
   */
  operator T()
  {
    return (m_value);
  }

protected:
  T m_value;
  Capsule* const* m_listeners;
};

/**
 * Boolean Connector with value filtering, i.e. on value change
 * scheduling.
 */
typedef Connector<bool,true> Signal;

};
#endif
<|endoftext|>


<commit_before>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department,
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.
 * No use of the CONDOR Software Program Source Code is authorized
 * without the express consent of the CONDOR Team.  For more information
 * contact: CONDOR Team, Attention: Professor Miron Livny,
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685,
 * (608) 262-0856 or miron@cs.wisc.edu.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure
 * by the U.S. Government is subject to restrictions as set forth in
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR
 * 52.227-19, as applicable, CONDOR Team, Attention: Professor Miron
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison,
 * WI 53706-1685, (608) 262-0856 or miron@cs.wisc.edu.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

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

#include "condor_common.h"
#include <iostream.h>
#include "condor_commands.h"
#include "condor_config.h"
#include "condor_classad.h"
#include "condor_debug.h"
#include "condor_io.h"
#include "MyString.h"

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

struct LineRec {
  MyString Name;
  float Priority;
  int Res;
  float AccUsage;
  float Factor;
  int BeginUsage;
};

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

static void usage(char* name);
static void ProcessInfo(AttrList* ad);
static int CountElem(AttrList* ad);
static void CollectInfo(int numElem, AttrList* ad, LineRec* LR);
static void PrintInfo(AttrList* ad, LineRec* LR, int NumElem);
static char* format_date( time_t);

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

extern "C" {
int CompPrio(LineRec* a, LineRec* b);
}

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

int DetailFlag=0;

main(int argc, char* argv[])
{

  int ResetUsage=0;
  int SetFactor=0;
  int SetPrio=0;
  bool ResetAll=false;

  for (int i=1; i<argc; i++) {
    if (strcmp(argv[i],"-setprio")==0) {
      if (i+2>=argc) usage(argv[0]);
      SetPrio=i;
      i+=2;
    }
    else if (strcmp(argv[i],"-setfactor")==0) {
      if (i+2>=argc) usage(argv[0]);
      SetFactor=i;
      i+=2;
    }
    else if (strcmp(argv[i],"-resetusage")==0) {
      if (i+1>=argc) usage(argv[0]);
      ResetUsage=i;
      i+=1;
    }
    else if (strcmp(argv[i],"-resetall")==0) {
      ResetAll=true;
    }
    else if (strcmp(argv[i],"-all")==0) {
      DetailFlag=1;
    }
    else if (strcmp(argv[i],"-usage")==0) {
      DetailFlag=2;
    }
    else {
      usage(argv[0]);
    }
  }

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

  config( 0 );
  char* NegotiatorHost = param( "NEGOTIATOR_HOST" );
  if (!NegotiatorHost) {
    fprintf( stderr, "No NegotiatorHost host specified in config file\n" );
	exit(1);
  }

  if (SetPrio) { // set priority

    char* tmp;
	if( ! (tmp = strchr(argv[SetPrio+1], '@')) ) {
		fprintf( stderr,
				 "%s: You must specify the full name of the submittor you wish\n",
				 argv[0] );
		fprintf( stderr, "\tto update the priority of (%s or %s)\n",
				 "user@uid.domain", "user@full.host.name" );
		exit(1);
	}
    float Priority=atof(argv[SetPrio+2]);

    // send request
    ReliSock sock(NegotiatorHost, NEGOTIATOR_PORT);
    sock.encode();
    if (!sock.put(SET_PRIORITY) ||
        !sock.put(argv[SetPrio+1]) ||
        !sock.put(Priority) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to send SET_PRIORITY command to negotiator\n" );
      exit(1);
    }

    printf("The priority of %s was set to %f\n",argv[SetPrio+1],Priority);

  }

  else if (SetFactor) { // set priority

    char* tmp;
	if( ! (tmp = strchr(argv[SetFactor+1], '@')) ) {
		fprintf( stderr,
				 "%s: You must specify the full name of the submittor you wish\n",
				 argv[0] );
		fprintf( stderr, "\tto update the priority of (%s or %s)\n",
				 "user@uid.domain", "user@full.host.name" );
		exit(1);
	}
    float Factor=atof(argv[SetFactor+2]);

    // send request
    ReliSock sock(NegotiatorHost, NEGOTIATOR_PORT);
    sock.encode();
    if (!sock.put(SET_PRIORITYFACTOR) ||
        !sock.put(argv[SetFactor+1]) ||
        !sock.put(Factor) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to send SET_PRIORITYFACTOR command to negotiator\n" );
      exit(1);
    }

    printf("The priority factor of %s was set to %f\n",argv[SetFactor+1],Factor);

  }

  else if (ResetUsage) { // set priority

    char* tmp;
	if( ! (tmp = strchr(argv[ResetUsage+1], '@')) ) {
		fprintf( stderr,
				 "%s: You must specify the full name of the submittor you wish\n",
				 argv[0] );
		fprintf( stderr, "\tto update the priority of (%s or %s)\n",
				 "user@uid.domain", "user@full.host.name" );
		exit(1);
	}

    // send request
    ReliSock sock(NegotiatorHost, NEGOTIATOR_PORT);
    sock.encode();
    if (!sock.put(RESET_USAGE) ||
        !sock.put(argv[ResetUsage+1]) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to send RESET_USAGE command to negotiator\n" );
      exit(1);
    }

    printf("The accumulated usage of %s was reset\n",argv[ResetUsage+1]);

  }

  else if (ResetAll) {

    // send request
    ReliSock sock(NegotiatorHost, NEGOTIATOR_PORT);
    sock.encode();
    if (!sock.put(RESET_ALL_USAGE) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to send RESET_ALL_USAGE command to negotiator\n" );
      exit(1);
    }

    printf("The accumulated usage was reset for all users\n");

  }

  else {  // list priorities

    // send request
    ReliSock sock(NegotiatorHost, NEGOTIATOR_PORT);
    sock.encode();
    if (!sock.put(GET_PRIORITY) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to send GET_PRIORITY command to negotiator\n" );
      exit(1);
    }

    // get reply
    sock.decode();
    AttrList* ad=new AttrList();
    if (!ad->get(sock) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to get classad from negotiator\n" );
      exit(1);
    }

    ProcessInfo(ad);
  }

  exit(0);
}

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

static void ProcessInfo(AttrList* ad)
{
  int NumElem=CountElem(ad);
  LineRec* LR=new LineRec[NumElem];
  CollectInfo(NumElem,ad,LR);
  qsort(LR,NumElem,sizeof(LineRec),CompPrio);
  PrintInfo(ad,LR,NumElem);
}

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

static int CountElem(AttrList* ad)
{
	int numSubmittors;
	if( ad->LookupInteger( "NumSubmittors", numSubmittors ) )
		return numSubmittors;
	else
		return -1;
}

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

extern "C" {
int CompPrio(LineRec* a, LineRec* b)
{
  if (DetailFlag==2) {
    if (a->AccUsage>b->AccUsage) return 1;
  }
  else {
    if (a->Priority>b->Priority) return 1;
  }
  return -1;
}
}

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

static void CollectInfo(int numElem, AttrList* ad, LineRec* LR)
{
  char  attrName[32], attrPrio[32], attrResUsed[32], attrFactor[32], attrBeginUsage[32], attrAccUsage[32];
  char  name[128];
  float priority, Factor, AccUsage;
  int   resUsed, BeginUsage;

  for( int i=1; i<=numElem; i++) {
    LR[i-1].Priority=0;
    sprintf( attrName , "Name%d", i );
    sprintf( attrPrio , "Priority%d", i );
    sprintf( attrResUsed , "ResourcesUsed%d", i );
    sprintf( attrFactor , "PriorityFactor%d", i );
    sprintf( attrBeginUsage , "BeginUsageTime%d", i );
    sprintf( attrAccUsage , "AccumulatedUsage%d", i );

    if( !ad->LookupString	( attrName, name ) 		||
		!ad->LookupFloat	( attrPrio, priority ) )
			continue;

	if(	!ad->LookupFloat	( attrFactor, Factor )	||
		!ad->LookupFloat	( attrAccUsage, AccUsage )	||
		!ad->LookupInteger	( attrBeginUsage, BeginUsage )	||
		!ad->LookupInteger	( attrResUsed, resUsed ) )
			DetailFlag=0;

    LR[i-1].Name=name;
    LR[i-1].Priority=priority;
    LR[i-1].Res=resUsed;
    LR[i-1].Factor=Factor;
    LR[i-1].BeginUsage=BeginUsage;
    LR[i-1].AccUsage=AccUsage;
  }

  // ad->fPrint(stdout);

  return;
}

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

static void PrintInfo(AttrList* ad, LineRec* LR, int NumElem)
{
  ExprTree* exp;
  ad->ResetExpr();
  exp=ad->NextExpr();
  time_t T=((Integer*) exp->RArg())->Value();
  printf("Last Priority Update: %s\n",format_date(T));

  LineRec Totals;
  Totals.Res=0;
  Totals.BeginUsage=0;
  Totals.AccUsage=0;

  char* Fmt1="%-30s %14.2f\n";  // Data line format
  char* Fmt2="%-30s %14s\n";    // Title and separator line format
  char* Fmt3="Number of users: %-13d %14s\n";    // Totals line format

  if (DetailFlag==1) {
    Fmt1="%-30s %14.2f %8.2f %12.2f %4d %12.2f %11s\n";
    Fmt2="%-30s %14s %8s %12s %4s %12s %11s\n";
    Fmt3="Number of users: %-13d %14s %8s %12s %4d %12.2f %11s\n";
  }
  else if (DetailFlag==2) {
    Fmt1="%-30s %12.2f %11s\n";
    Fmt2="%-30s %12s %11s\n";
    Fmt3="Number of users: %-13d %12.2f %11s\n";
  }

  if (DetailFlag==2) {
    printf(Fmt2,"         ","Accumulated","   Usage  ");
    printf(Fmt2,"User Name","Usage (hrs)","Start Time");
    printf(Fmt2,"------------------------------","-----------","----------");
  }
  else {
    printf(Fmt2,"         ","Effective","  Real  ","  Priority  ","Res ","Accumulated","   Usage  ");
    printf(Fmt2,"User Name","Priority ","Priority","   Factor   ","Used","Usage (hrs)","Start Time");
    printf(Fmt2,"------------------------------","---------","--------","------------","----","-----------","----------");
  }

  for (int i=0; i<NumElem; i++) {
    if (LR[i].Name.Length()>30) LR[i].Name=LR[i].Name.Substr(0,29);
    if (DetailFlag==2)
      printf(Fmt1,LR[i].Name.Value(),LR[i].AccUsage/3600.0,format_date(LR[i].BeginUsage));
    else
      printf(Fmt1,LR[i].Name.Value(),LR[i].Priority,(LR[i].Priority/LR[i].Factor),LR[i].Factor,LR[i].Res,LR[i].AccUsage/3600.0,format_date(LR[i].BeginUsage));
    Totals.Res+=LR[i].Res;
    Totals.AccUsage+=LR[i].AccUsage;
    if (LR[i].BeginUsage<Totals.BeginUsage || Totals.BeginUsage==0) Totals.BeginUsage=LR[i].BeginUsage;
  }

  if (DetailFlag==2) {
    printf(Fmt2,"------------------------------","-----------","----------");
    printf(Fmt3,NumElem,Totals.AccUsage/3600.0,format_date(Totals.BeginUsage));
  }
  else {
    printf(Fmt2,"------------------------------","---------","--------","------------","----","-----------","----------");
    printf(Fmt3,NumElem,"","","",Totals.Res,Totals.AccUsage/3600.0,format_date(Totals.BeginUsage));
  }

  return;
}

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

static void usage(char* name) {
  fprintf( stderr, "usage: %s [ -all | { -setprio | -setfactor }  user value | -resetusage user | -resetall ]\n", name );
  exit(1);
}

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

/*
  Format a date expressed in "UNIX time" into "month/day hour:minute".
*/

static char* format_date( time_t date )
{
        static char     buf[ 12 ];
        struct tm       *tm;

        if (date==0) return " ??? ";

        tm = localtime( &date );
        sprintf( buf, "%2d/%-2d %02d:%02d",
                (tm->tm_mon)+1, tm->tm_mday, tm->tm_hour, tm->tm_min
        );
        return buf;
}
<commit_msg>Changed the start time to match time in the new resource list option output<commit_after>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department,
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.
 * No use of the CONDOR Software Program Source Code is authorized
 * without the express consent of the CONDOR Team.  For more information
 * contact: CONDOR Team, Attention: Professor Miron Livny,
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685,
 * (608) 262-0856 or miron@cs.wisc.edu.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure
 * by the U.S. Government is subject to restrictions as set forth in
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR
 * 52.227-19, as applicable, CONDOR Team, Attention: Professor Miron
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison,
 * WI 53706-1685, (608) 262-0856 or miron@cs.wisc.edu.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

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

#include "condor_common.h"
#include <iostream.h>
#include "condor_commands.h"
#include "condor_config.h"
#include "condor_classad.h"
#include "condor_debug.h"
#include "condor_io.h"
#include "MyString.h"
#include "format_time.h"

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

struct LineRec {
  MyString Name;
  float Priority;
  int Res;
  float AccUsage;
  float Factor;
  int BeginUsage;
};

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

static void usage(char* name);
static void ProcessInfo(AttrList* ad);
static int CountElem(AttrList* ad);
static void CollectInfo(int numElem, AttrList* ad, LineRec* LR);
static void PrintInfo(AttrList* ad, LineRec* LR, int NumElem);
static void PrintResList(AttrList* ad);

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

extern "C" {
int CompPrio(LineRec* a, LineRec* b);
}

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

int DetailFlag=0;

main(int argc, char* argv[])
{

  int ResetUsage=0;
  int SetFactor=0;
  int SetPrio=0;
  bool ResetAll=false;
  int GetResList=0;

  for (int i=1; i<argc; i++) {
    if (strcmp(argv[i],"-setprio")==0) {
      if (i+2>=argc) usage(argv[0]);
      SetPrio=i;
      i+=2;
    }
    else if (strcmp(argv[i],"-setfactor")==0) {
      if (i+2>=argc) usage(argv[0]);
      SetFactor=i;
      i+=2;
    }
    else if (strcmp(argv[i],"-resetusage")==0) {
      if (i+1>=argc) usage(argv[0]);
      ResetUsage=i;
      i+=1;
    }
    else if (strcmp(argv[i],"-resetall")==0) {
      ResetAll=true;
    }
    else if (strcmp(argv[i],"-all")==0) {
      DetailFlag=1;
    }
    else if (strcmp(argv[i],"-usage")==0) {
      DetailFlag=2;
    }
    else if (strcmp(argv[i],"-getreslist")==0) {
      GetResList=i;
      i+=1;
    }
    else {
      usage(argv[0]);
    }
  }

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

  config( 0 );
  char* NegotiatorHost = param( "NEGOTIATOR_HOST" );
  if (!NegotiatorHost) {
    fprintf( stderr, "No NegotiatorHost host specified in config file\n" );
	exit(1);
  }

  if (SetPrio) { // set priority

    char* tmp;
	if( ! (tmp = strchr(argv[SetPrio+1], '@')) ) {
		fprintf( stderr,
				 "%s: You must specify the full name of the submittor you wish\n",
				 argv[0] );
		fprintf( stderr, "\tto update the priority of (%s or %s)\n",
				 "user@uid.domain", "user@full.host.name" );
		exit(1);
	}
    float Priority=atof(argv[SetPrio+2]);

    // send request
    ReliSock sock(NegotiatorHost, NEGOTIATOR_PORT);
    sock.encode();
    if (!sock.put(SET_PRIORITY) ||
        !sock.put(argv[SetPrio+1]) ||
        !sock.put(Priority) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to send SET_PRIORITY command to negotiator\n" );
      exit(1);
    }

    printf("The priority of %s was set to %f\n",argv[SetPrio+1],Priority);

  }

  else if (SetFactor) { // set priority

    char* tmp;
	if( ! (tmp = strchr(argv[SetFactor+1], '@')) ) {
		fprintf( stderr,
				 "%s: You must specify the full name of the submittor you wish\n",
				 argv[0] );
		fprintf( stderr, "\tto update the priority of (%s or %s)\n",
				 "user@uid.domain", "user@full.host.name" );
		exit(1);
	}
    float Factor=atof(argv[SetFactor+2]);

    // send request
    ReliSock sock(NegotiatorHost, NEGOTIATOR_PORT);
    sock.encode();
    if (!sock.put(SET_PRIORITYFACTOR) ||
        !sock.put(argv[SetFactor+1]) ||
        !sock.put(Factor) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to send SET_PRIORITYFACTOR command to negotiator\n" );
      exit(1);
    }

    printf("The priority factor of %s was set to %f\n",argv[SetFactor+1],Factor);

  }

  else if (ResetUsage) { // set priority

    char* tmp;
	if( ! (tmp = strchr(argv[ResetUsage+1], '@')) ) {
		fprintf( stderr,
				 "%s: You must specify the full name of the submittor you wish\n",
				 argv[0] );
		fprintf( stderr, "\tto update the priority of (%s or %s)\n",
				 "user@uid.domain", "user@full.host.name" );
		exit(1);
	}

    // send request
    ReliSock sock(NegotiatorHost, NEGOTIATOR_PORT);
    sock.encode();
    if (!sock.put(RESET_USAGE) ||
        !sock.put(argv[ResetUsage+1]) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to send RESET_USAGE command to negotiator\n" );
      exit(1);
    }

    printf("The accumulated usage of %s was reset\n",argv[ResetUsage+1]);

  }

  else if (ResetAll) {

    // send request
    ReliSock sock(NegotiatorHost, NEGOTIATOR_PORT);
    sock.encode();
    if (!sock.put(RESET_ALL_USAGE) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to send RESET_ALL_USAGE command to negotiator\n" );
      exit(1);
    }

    printf("The accumulated usage was reset for all users\n");

  }

  else if (GetResList) { // set priority

    char* tmp;
	if( ! (tmp = strchr(argv[GetResList+1], '@')) ) {
		fprintf( stderr,
				 "%s: You must specify the full name of the submittor you wish\n",
				 argv[0] );
		fprintf( stderr, "\tto update the priority of (%s or %s)\n",
				 "user@uid.domain", "user@full.host.name" );
		exit(1);
	}

    // send request
    ReliSock sock(NegotiatorHost, NEGOTIATOR_PORT);
    sock.encode();
    if (!sock.put(GET_RESLIST) ||
        !sock.put(argv[GetResList+1]) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to send GET_RESLIST command to negotiator\n" );
      exit(1);
    }

    // get reply
    sock.decode();
    AttrList* ad=new AttrList();
    if (!ad->get(sock) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to get classad from negotiator\n" );
      exit(1);
    }

    PrintResList(ad);
  }

  else {  // list priorities

    // send request
    ReliSock sock(NegotiatorHost, NEGOTIATOR_PORT);
    sock.encode();
    if (!sock.put(GET_PRIORITY) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to send GET_PRIORITY command to negotiator\n" );
      exit(1);
    }

    // get reply
    sock.decode();
    AttrList* ad=new AttrList();
    if (!ad->get(sock) ||
        !sock.end_of_message()) {
      fprintf( stderr, "failed to get classad from negotiator\n" );
      exit(1);
    }

    ProcessInfo(ad);
  }

  exit(0);
}

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

static void ProcessInfo(AttrList* ad)
{
  int NumElem=CountElem(ad);
  LineRec* LR=new LineRec[NumElem];
  CollectInfo(NumElem,ad,LR);
  qsort(LR,NumElem,sizeof(LineRec),CompPrio);
  PrintInfo(ad,LR,NumElem);
}

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

static int CountElem(AttrList* ad)
{
	int numSubmittors;
	if( ad->LookupInteger( "NumSubmittors", numSubmittors ) )
		return numSubmittors;
	else
		return -1;
}

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

extern "C" {
int CompPrio(LineRec* a, LineRec* b)
{
  if (DetailFlag==2) {
    if (a->AccUsage>b->AccUsage) return 1;
  }
  else {
    if (a->Priority>b->Priority) return 1;
  }
  return -1;
}
}

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

static void CollectInfo(int numElem, AttrList* ad, LineRec* LR)
{
  char  attrName[32], attrPrio[32], attrResUsed[32], attrFactor[32], attrBeginUsage[32], attrAccUsage[32];
  char  name[128];
  float priority, Factor, AccUsage;
  int   resUsed, BeginUsage;

  for( int i=1; i<=numElem; i++) {
    LR[i-1].Priority=0;
    sprintf( attrName , "Name%d", i );
    sprintf( attrPrio , "Priority%d", i );
    sprintf( attrResUsed , "ResourcesUsed%d", i );
    sprintf( attrFactor , "PriorityFactor%d", i );
    sprintf( attrBeginUsage , "BeginUsageTime%d", i );
    sprintf( attrAccUsage , "AccumulatedUsage%d", i );

    if( !ad->LookupString	( attrName, name ) 		||
		!ad->LookupFloat	( attrPrio, priority ) )
			continue;

	if(	!ad->LookupFloat	( attrFactor, Factor )	||
		!ad->LookupFloat	( attrAccUsage, AccUsage )	||
		!ad->LookupInteger	( attrBeginUsage, BeginUsage )	||
		!ad->LookupInteger	( attrResUsed, resUsed ) )
			DetailFlag=0;

    LR[i-1].Name=name;
    LR[i-1].Priority=priority;
    LR[i-1].Res=resUsed;
    LR[i-1].Factor=Factor;
    LR[i-1].BeginUsage=BeginUsage;
    LR[i-1].AccUsage=AccUsage;
  }

  // ad->fPrint(stdout);

  return;
}

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

static void PrintInfo(AttrList* ad, LineRec* LR, int NumElem)
{
  ExprTree* exp;
  ad->ResetExpr();
  exp=ad->NextExpr();
  time_t T=((Integer*) exp->RArg())->Value();
  printf("Last Priority Update: %s\n",format_date(T));

  LineRec Totals;
  Totals.Res=0;
  Totals.BeginUsage=0;
  Totals.AccUsage=0;

  char* Fmt1="%-30s %14.2f\n";  // Data line format
  char* Fmt2="%-30s %14s\n";    // Title and separator line format
  char* Fmt3="Number of users: %-13d %14s\n";    // Totals line format

  if (DetailFlag==1) {
    Fmt1="%-30s %14.2f %8.2f %12.2f %4d %12.2f %11s\n";
    Fmt2="%-30s %14s %8s %12s %4s %12s %11s\n";
    Fmt3="Number of users: %-13d %14s %8s %12s %4d %12.2f %11s\n";
  }
  else if (DetailFlag==2) {
    Fmt1="%-30s %12.2f %11s\n";
    Fmt2="%-30s %12s %11s\n";
    Fmt3="Number of users: %-13d %12.2f %11s\n";
  }

  if (DetailFlag==2) {
    printf(Fmt2,"         ","Accumulated","   Usage  ");
    printf(Fmt2,"User Name","Usage (hrs)","Start Time");
    printf(Fmt2,"------------------------------","-----------","----------");
  }
  else {
    printf(Fmt2,"         ","Effective","  Real  ","  Priority  ","Res ","Accumulated","   Usage  ");
    printf(Fmt2,"User Name","Priority ","Priority","   Factor   ","Used","Usage (hrs)","Start Time");
    printf(Fmt2,"------------------------------","---------","--------","------------","----","-----------","----------");
  }

  for (int i=0; i<NumElem; i++) {
    if (LR[i].Name.Length()>30) LR[i].Name=LR[i].Name.Substr(0,29);
    if (DetailFlag==2)
      printf(Fmt1,LR[i].Name.Value(),LR[i].AccUsage/3600.0,format_date(LR[i].BeginUsage));
    else
      printf(Fmt1,LR[i].Name.Value(),LR[i].Priority,(LR[i].Priority/LR[i].Factor),LR[i].Factor,LR[i].Res,LR[i].AccUsage/3600.0,format_date(LR[i].BeginUsage));
    Totals.Res+=LR[i].Res;
    Totals.AccUsage+=LR[i].AccUsage;
    if (LR[i].BeginUsage<Totals.BeginUsage || Totals.BeginUsage==0) Totals.BeginUsage=LR[i].BeginUsage;
  }

  if (DetailFlag==2) {
    printf(Fmt2,"------------------------------","-----------","----------");
    printf(Fmt3,NumElem,Totals.AccUsage/3600.0,format_date(Totals.BeginUsage));
  }
  else {
    printf(Fmt2,"------------------------------","---------","--------","------------","----","-----------","----------");
    printf(Fmt3,NumElem,"","","",Totals.Res,Totals.AccUsage/3600.0,format_date(Totals.BeginUsage));
  }

  return;
}

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

static void usage(char* name) {
  fprintf( stderr, "usage: %s [ -all | { -setprio | -setfactor }  user value | -resetusage user | -resetall ]\n", name );
  exit(1);
}

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

static void PrintResList(AttrList* ad)
{
  // ad->fPrint(stdout);

  char  attrName[32], attrStartTime[32];
  char  name[128];
  int   StartTime;

  char* Fmt="%-30s %12s\n";

  printf(Fmt,"Resource Name"," Match Time");
  printf(Fmt,"-------------"," ----------");

  int i;

  for (i=1;;i++) {
    sprintf( attrName , "Name%d", i );
    sprintf( attrStartTime , "StartTime%d", i );

    if( !ad->LookupString   ( attrName, name ) ||
		!ad->LookupInteger  ( attrStartTime, StartTime))
            break;

    char* p=strrchr(name,'@');
    *p='\0';
    time_t Now=time(0)-StartTime;
	printf(Fmt,name,format_time(Now));
  }

  printf(Fmt,"-------------"," ----------");
  printf("Number of Resources Used: %d\n",i-1);

  return;
}

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

<|endoftext|>


<commit_before>/***************************************************************************
**
** This file is part of the qmlogre example on http://qt.gitorious.org.
**
** Copyright (c) 2011 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 <OGRE/RenderSystems/GL/OgreGLTexture.h>
#include <OGRE/RenderSystems/GL/OgreGLFrameBufferObject.h>
#include <OGRE/RenderSystems/GL/OgreGLFBORenderTexture.h>

#include "../config.h"
#include "ogreitem.h"
#include "cameranodeobject.h"

#include <OGRE/Ogre.h>

#include <QtCore/QPropertyAnimation>
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtOpenGL/QGLFunctions>
#include <QtQuick/QQuickWindow>
#include <QtQuick/QSGSimpleTextureNode>

static QString appPath()
{
    QString path = QCoreApplication::applicationDirPath();
    QDir dir(path);
#ifdef Q_WS_MAC
    dir.cdUp();
    dir.cdUp();
    dir.cdUp();
#elif defined(Q_WS_WIN)
    dir.cdUp();
#endif
    return dir.absolutePath();
}

OgreItem::OgreItem(QQuickItem *parent)
    : QQuickItem(parent)
    , m_timerID(0)
    , m_node(0)
    , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
    , m_texture(0)
    , m_samples(0)
    , m_AAEnabled(false)
    , m_renderTexture(0)
    , m_ogreFBO(0)
    , m_initialized(false)
    , m_dirtyFBO(false)
{
    setFlag(ItemHasContents);
    setSmooth(false);

    startTimer(16);
}

OgreItem::~OgreItem()
{
    if (m_renderTexture) {
        m_renderTexture->removeAllViewports();
    }

    if (m_root) {
        m_root->detachRenderTarget(m_renderTexture);

        if (m_sceneManager) {
            m_root->destroySceneManager(m_sceneManager);
        }
    }

    delete m_root;
}

QSGNode *OgreItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    if (width() <= 0 || height() <= 0) {
        delete oldNode;
        return 0;
    }

    m_node = static_cast<QSGSimpleTextureNode *>(oldNode);
    if (!m_node)
    {
        m_node = new QSGSimpleTextureNode();
        m_node->setFiltering(QSGTexture::Nearest);
        m_node->setMaterial(&m_material);
        m_node->setOpaqueMaterial(&m_materialO);
        m_node->setGeometry(&m_geometry);
        m_node->setFlag(QSGNode::UsePreprocess);
    }
    m_node->setRect(boundingRect());

    setSize(QSize(width(), height()));
    setAAEnabled(smooth());

    // Render Ogre!
    restoreOgreState();

    if (!m_initialized)
        init();

    if (m_dirtyFBO)
        updateFBO();

    m_renderTexture->update(true);
    m_node->markDirty(QSGNode::DirtyMaterial);

    saveOgreState();
    // Done rendering.

    m_node->setTexture(m_texture);

    m_cameraQObject = static_cast<QObject *>(m_cameraObject);

    return m_node;
}

void OgreItem::timerEvent(QTimerEvent *)
{
    update();
}

void OgreItem::saveOgreState()
{
    m_ogreFBO = getOgreFBO();

    const QGLContext *ctx = QGLContext::currentContext();
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    ctx->functions()->glBindBuffer(GL_ARRAY_BUFFER, 0);
    ctx->functions()->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    ctx->functions()->glBindRenderbuffer(GL_RENDERBUFFER, 0);
    ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
}

void OgreItem::restoreOgreState()
{
    const QGLContext *ctx = QGLContext::currentContext();
    glPopAttrib();
    ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_ogreFBO);
    ctx->functions()->glUseProgram(0);
}

GLuint OgreItem::getOgreFBO()
{
    if (!m_renderTexture)
        return 0;

    Ogre::GLFrameBufferObject *ogreFbo = 0;
    m_renderTexture->getCustomAttribute("FBO", &ogreFbo);
    Ogre::GLFBOManager *manager = ogreFbo->getManager();
    manager->bind(m_renderTexture);

    GLint id;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &id);

    const QGLContext *ctx = QGLContext::currentContext();
    ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);

    return id;
}

void OgreItem::updateFBO()
{
    if (m_renderTexture)
        Ogre::TextureManager::getSingleton().remove("RttTex");

    rtt_texture = Ogre::TextureManager::getSingleton().createManual("RttTex",
                                                                    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                                                                    Ogre::TEX_TYPE_2D,
                                                                    m_size.width(),
                                                                    m_size.height(),
                                                                    0,
                                                                    Ogre::PF_R8G8B8A8,
                                                                    Ogre::TU_RENDERTARGET, 0, false,
                                                                    m_AAEnabled ? m_samples : 0);

    m_renderTexture = rtt_texture->getBuffer()->getRenderTarget();

    m_renderTexture->addViewport(m_camera);
    m_renderTexture->getViewport(0)->setClearEveryFrame(true);
    m_renderTexture->getViewport(0)->setBackgroundColour(Ogre::ColourValue::Black);
    m_renderTexture->getViewport(0)->setOverlaysEnabled(false);

    Ogre::Real aspectRatio = Ogre::Real(m_size.width()) / Ogre::Real(m_size.height());
    m_camera->setAspectRatio(aspectRatio);

    QSGGeometry::updateTexturedRectGeometry(&m_geometry,
                                            QRectF(0, 0, m_size.width(), m_size.height()),
                                            QRectF(0, 0, 1, 1));

    Ogre::GLTexture *nativeTexture = static_cast<Ogre::GLTexture *>(rtt_texture.get());

    delete m_texture;
    m_texture = window()->createTextureFromId(nativeTexture->getGLID(), m_size);
    m_texture->setFiltering(QSGTexture::Nearest);
    m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
    m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge);

    m_material.setTexture(m_texture);
    m_materialO.setTexture(m_texture);
}

void OgreItem::setSize(const QSize &size)
{
    if (size == m_size)
        return;

    m_size = size;
    m_dirtyFBO = true;
    m_node->markDirty(QSGNode::DirtyGeometry);
}

void OgreItem::setAAEnabled(bool enable)
{
    if (m_AAEnabled == enable)
        return;

    m_AAEnabled = enable;
    m_dirtyFBO = true;
    // markDirty(DirtyMaterial) gets called every frame, so we don't actually need to call it here.
    //m_node->markDirty(QSGNode::DirtyMaterial);
}

void OgreItem::init()
{
    const QGLContext *ctx = QGLContext::currentContext();
    QGLFormat format = ctx->format();
    m_samples = format.sampleBuffers() ? format.samples() : 0;

    m_root = new Ogre::Root;
    m_root->loadPlugin(QLatin1String(OGRE_RenderSystem_GL_LIBRARY).latin1());

    Ogre::RenderSystem *renderSystem = m_root->getRenderSystemByName("OpenGL Rendering Subsystem");
    m_root->setRenderSystem(renderSystem);
    m_root->initialise(false);

    Ogre::NameValuePairList params;

    params["externalGLControl"] = "true";
    params["currentGLContext"] = "true";
	params["macAPI"] = "cocoa";
	//params["macAPICocoaUseNSView"] = "true";

    //Finally create our window.
    m_window = m_root->createRenderWindow("OgreWindow", 1, 1, false, &params);
    m_window->setVisible(false);
    m_window->update(false);

    // Load resources
    Ogre::ResourceGroupManager::getSingleton().addResourceLocation((appPath() + "/../../resources/data.zip").toLatin1().data(), "Zip");
    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

    // Setup scene
    m_sceneManager = m_root->createSceneManager(Ogre::ST_GENERIC, "mySceneManager");
    m_camera = m_sceneManager->createCamera("myCamera");
    m_camera->setNearClipDistance(1);
    m_camera->setFarClipDistance(99999);
    m_camera->setAspectRatio(Ogre::Real(m_size.width()) / Ogre::Real(m_size.height()));

    // Setup content...

    // Set a sky dome
    m_sceneManager->setSkyBox(true, "SpaceSkyBox", 10000);

    // setup some basic lighting for our scene
    m_sceneManager->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3));
    m_sceneManager->createLight("myLight")->setPosition(20, 80, 50);

    // create an ogre head entity and place it at the origin
    m_sceneManager->getRootSceneNode()->attachObject(m_sceneManager->createEntity("Head", "ogrehead.mesh"));

    // Setup the camera
    m_cameraObject = new CameraNodeObject(m_camera);
    m_cameraObject->camera()->setAutoTracking(true, m_sceneManager->getRootSceneNode());

    m_initialized = true;
}
<commit_msg>Applied qmlogre patch.<commit_after>/***************************************************************************
**
** This file is part of the qmlogre example on http://qt.gitorious.org.
**
** Copyright (c) 2011 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 <OGRE/RenderSystems/GL/OgreGLTexture.h>
#include <OGRE/RenderSystems/GL/OgreGLFrameBufferObject.h>
#include <OGRE/RenderSystems/GL/OgreGLFBORenderTexture.h>

#include "../config.h"
#include "ogreitem.h"
#include "cameranodeobject.h"

#include <OGRE/Ogre.h>

#include <QtCore/QPropertyAnimation>
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtOpenGL/QGLFunctions>
#include <QtQuick/QQuickWindow>
#include <QtQuick/QSGSimpleTextureNode>

static QString appPath()
{
    QString path = QCoreApplication::applicationDirPath();
    QDir dir(path);
#ifdef Q_WS_MAC
    dir.cdUp();
    dir.cdUp();
    dir.cdUp();
#elif defined(Q_WS_WIN)
    dir.cdUp();
#endif
    return dir.absolutePath();
}

OgreItem::OgreItem(QQuickItem *parent)
    : QQuickItem(parent)
    , m_timerID(0)
    , m_node(0)
    , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
    , m_texture(0)
    , m_samples(0)
    , m_AAEnabled(false)
    , m_renderTexture(0)
    , m_ogreFBO(0)
    , m_initialized(false)
    , m_dirtyFBO(false)
{
    setFlag(ItemHasContents);
    setSmooth(false);

    startTimer(16);
}

OgreItem::~OgreItem()
{
	rtt_texture.setNull();

    if (m_renderTexture) {
        m_renderTexture->removeAllViewports();
    }

    if (m_root) {
        m_root->detachRenderTarget(m_renderTexture);

        if (m_sceneManager) {
            m_root->destroySceneManager(m_sceneManager);
        }
    }

    delete m_root;
}

QSGNode *OgreItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    if (width() <= 0 || height() <= 0) {
        delete oldNode;
        return 0;
    }

    m_node = static_cast<QSGSimpleTextureNode *>(oldNode);
    if (!m_node)
    {
        m_node = new QSGSimpleTextureNode();
        m_node->setFiltering(QSGTexture::Nearest);
        m_node->setMaterial(&m_material);
        m_node->setOpaqueMaterial(&m_materialO);
        m_node->setGeometry(&m_geometry);
        m_node->setFlag(QSGNode::UsePreprocess);
    }
    m_node->setRect(boundingRect());

    setSize(QSize(width(), height()));
    setAAEnabled(smooth());

    // Render Ogre!
    restoreOgreState();

    if (!m_initialized)
        init();

    if (m_dirtyFBO)
        updateFBO();

    m_renderTexture->update(true);
    m_node->markDirty(QSGNode::DirtyMaterial);

    saveOgreState();
    // Done rendering.

    m_node->setTexture(m_texture);

    m_cameraQObject = static_cast<QObject *>(m_cameraObject);

    return m_node;
}

void OgreItem::timerEvent(QTimerEvent *)
{
    update();
}

void OgreItem::saveOgreState()
{
    m_ogreFBO = getOgreFBO();

    const QGLContext *ctx = QGLContext::currentContext();
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    ctx->functions()->glBindBuffer(GL_ARRAY_BUFFER, 0);
    ctx->functions()->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    ctx->functions()->glBindRenderbuffer(GL_RENDERBUFFER, 0);
    ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
}

void OgreItem::restoreOgreState()
{
    const QGLContext *ctx = QGLContext::currentContext();
    glPopAttrib();
    ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_ogreFBO);
    ctx->functions()->glUseProgram(0);
}

GLuint OgreItem::getOgreFBO()
{
    if (!m_renderTexture)
        return 0;

    Ogre::GLFrameBufferObject *ogreFbo = 0;
    m_renderTexture->getCustomAttribute("FBO", &ogreFbo);
    Ogre::GLFBOManager *manager = ogreFbo->getManager();
    manager->bind(m_renderTexture);

    GLint id;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &id);

    const QGLContext *ctx = QGLContext::currentContext();
    ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);

    return id;
}

void OgreItem::updateFBO()
{
    if (m_renderTexture)
        Ogre::TextureManager::getSingleton().remove("RttTex");

    rtt_texture = Ogre::TextureManager::getSingleton().createManual("RttTex",
                                                                    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                                                                    Ogre::TEX_TYPE_2D,
                                                                    m_size.width(),
                                                                    m_size.height(),
                                                                    0,
                                                                    Ogre::PF_R8G8B8A8,
                                                                    Ogre::TU_RENDERTARGET, 0, false,
                                                                    m_AAEnabled ? m_samples : 0);

    m_renderTexture = rtt_texture->getBuffer()->getRenderTarget();

    m_renderTexture->addViewport(m_camera);
    m_renderTexture->getViewport(0)->setClearEveryFrame(true);
    m_renderTexture->getViewport(0)->setBackgroundColour(Ogre::ColourValue::Black);
    m_renderTexture->getViewport(0)->setOverlaysEnabled(false);

    Ogre::Real aspectRatio = Ogre::Real(m_size.width()) / Ogre::Real(m_size.height());
    m_camera->setAspectRatio(aspectRatio);

    QSGGeometry::updateTexturedRectGeometry(&m_geometry,
                                            QRectF(0, 0, m_size.width(), m_size.height()),
                                            QRectF(0, 0, 1, 1));

    Ogre::GLTexture *nativeTexture = static_cast<Ogre::GLTexture *>(rtt_texture.get());

    delete m_texture;
    m_texture = window()->createTextureFromId(nativeTexture->getGLID(), m_size);
    m_texture->setFiltering(QSGTexture::Nearest);
    m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
    m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge);

    m_material.setTexture(m_texture);
    m_materialO.setTexture(m_texture);
}

void OgreItem::setSize(const QSize &size)
{
    if (size == m_size)
        return;

    m_size = size;
    m_dirtyFBO = true;
    m_node->markDirty(QSGNode::DirtyGeometry);
}

void OgreItem::setAAEnabled(bool enable)
{
    if (m_AAEnabled == enable)
        return;

    m_AAEnabled = enable;
    m_dirtyFBO = true;
    // markDirty(DirtyMaterial) gets called every frame, so we don't actually need to call it here.
    //m_node->markDirty(QSGNode::DirtyMaterial);
}

void OgreItem::init()
{
    const QGLContext *ctx = QGLContext::currentContext();
    QGLFormat format = ctx->format();
    m_samples = format.sampleBuffers() ? format.samples() : 0;

    m_root = new Ogre::Root;
    m_root->loadPlugin(QLatin1String(OGRE_RenderSystem_GL_LIBRARY).latin1());

    Ogre::RenderSystem *renderSystem = m_root->getRenderSystemByName("OpenGL Rendering Subsystem");
    m_root->setRenderSystem(renderSystem);
    m_root->initialise(false);

    Ogre::NameValuePairList params;

    params["externalGLControl"] = "true";
    params["currentGLContext"] = "true";
	params["macAPI"] = "cocoa";
	//params["macAPICocoaUseNSView"] = "true";

    //Finally create our window.
    m_window = m_root->createRenderWindow("OgreWindow", 1, 1, false, &params);
    m_window->setVisible(false);
    m_window->update(false);

    // Load resources
    Ogre::ResourceGroupManager::getSingleton().addResourceLocation((appPath() + "/../../resources/data.zip").toLatin1().data(), "Zip");
    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

    // Setup scene
    m_sceneManager = m_root->createSceneManager(Ogre::ST_GENERIC, "mySceneManager");
    m_camera = m_sceneManager->createCamera("myCamera");
    m_camera->setNearClipDistance(1);
    m_camera->setFarClipDistance(99999);
    m_camera->setAspectRatio(Ogre::Real(m_size.width()) / Ogre::Real(m_size.height()));

    // Setup content...

    // Set a sky dome
    m_sceneManager->setSkyBox(true, "SpaceSkyBox", 10000);

    // setup some basic lighting for our scene
    m_sceneManager->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3));
    m_sceneManager->createLight("myLight")->setPosition(20, 80, 50);

    // create an ogre head entity and place it at the origin
    m_sceneManager->getRootSceneNode()->attachObject(m_sceneManager->createEntity("Head", "ogrehead.mesh"));

    // Setup the camera
    m_cameraObject = new CameraNodeObject(m_camera);
    m_cameraObject->camera()->setAutoTracking(true, m_sceneManager->getRootSceneNode());

    m_initialized = true;
}
<|endoftext|>


<commit_before>#include <fmt/format.h>

#include "../python.hpp"
#include "../../string.hpp"
#include "../item.hpp"
#include "../plugin_handler.hpp"

using namespace bookwyrm;
using std::string;
using std::vector;

PYBIND11_MODULE(pybookwyrm, m)
{
    m.attr("__doc__") = "bookwyrm python bindings";

    /* core::item bindings */

    m.attr("empty") = core::empty;

    py::enum_<core::year_mod>(m, "year_mod")
        .value("equal", core::year_mod::equal)
        .value("eq_gt", core::year_mod::eq_gt)
        .value("eq_lt", core::year_mod::eq_lt)
        .value("lt",    core::year_mod::lt)
        .value("gt",    core::year_mod::gt);

    py::class_<core::exacts_t>(m, "exacts_t")
        .def_readonly("year",      &core::exacts_t::year)
        .def_readonly("extension", &core::exacts_t::extension)
        .def_readonly("volume",    &core::exacts_t::volume)
        .def_readonly("number",    &core::exacts_t::number)
        .def_readonly("pages",     &core::exacts_t::pages)
        /* .def_readwrite("lang",    &core::exacts_t::lang) */
        .def("__repr__", [](const core::exacts_t &c) {
            return fmt::format(
                "<pybookwyrm.exacts_t with fields:\n"
                "\tyear:      {}\n"
                "\tfile type: {}\n"
                "\tvolume:    {}\n"
                "\tnumber:    {}\n"
                "\tpages:     {}\n"
                "\tsize:      {}B\n",
                /* "\tlanguage:  {}\n>", */
                c.year, c.extension, c.volume,
                c.number, c.pages, c.size //, c.lang
            );
        });

    py::class_<core::nonexacts_t>(m, "nonexacts_t")
        .def_readonly("authors",   &core::nonexacts_t::authors)
        .def_readonly("title",     &core::nonexacts_t::title)
        .def_readonly("series",    &core::nonexacts_t::series)
        .def_readonly("publisher", &core::nonexacts_t::publisher)
        .def_readonly("journal",   &core::nonexacts_t::journal)
        .def_readonly("edition",   &core::nonexacts_t::edition)
        .def("__repr__", [](const core::nonexacts_t &c) {
            return fmt::format(
                "<pybookwyrm.nonexacts_t with fields:\n"
                "\ttitle:     '{}'\n"
                "\tserie:     '{}'\n"
                "\tedition:   '{}'\n"
                "\tpublisher: '{}'\n"
                "\tjournal:   '{}'\n"
                "\tauthors:   '{}'\n>",
                c.title, c.series, c.edition, c.publisher, c.journal,
                vector_to_string(c.authors)
            );
        });

    py::class_<core::misc_t>(m, "misc_t")
        .def_readonly("isbns", &core::misc_t::isbns)
        .def_readonly("uris", &core::misc_t::uris)
        .def("__repr__", [](const core::misc_t &c) {
            return fmt::format(
                "<pybookwyrn.misc_t with fields:\n"
                "\tisbns:     '{}'\n"
                "\turis:      '{}'\n",
                vector_to_string(c.isbns),
                vector_to_string(c.uris)
            );
        });

    py::class_<core::item>(m, "item")
        .def_readonly("nonexacts", &core::item::nonexacts)
        .def_readonly("exacts",    &core::item::exacts)
        .def("__repr__", [](const core::item &i) {
            return "<bookwyrm.item with title '" + i.nonexacts.title + "'>";
        });

    /* core::plugin_handler bindings */

    py::enum_<core::log_level>(m, "log_level")
        .value("debug", core::log_level::debug)
        .value("info",  core::log_level::info)
        .value("warn",  core::log_level::warn)
        .value("error", core::log_level::err);

    py::class_<core::plugin_handler>(m, "bookwyrm")
        .def("feed",        &core::plugin_handler::add_item)
        .def("log",         &core::plugin_handler::log);
}
<commit_msg>improve Python interface for core::item<commit_after>#include <fmt/format.h>

#include "../python.hpp"
#include "../../string.hpp"
#include "../item.hpp"
#include "../plugin_handler.hpp"

using namespace bookwyrm;
using std::string;
using std::vector;

static py::object getattr(const core::item &item, const std::string &key)
{
    /*
     * Exact attributes.
     * No reason to query a wanted item size.
     * TODO: add ymod.
     */
    if (key == "yearmod")
        return py::cast(item.exacts.ymod);
    else if (key == "year")
        return py::cast(item.exacts.year);
    else if (key == "volume")
        return py::cast(item.exacts.volume);
    else if (key == "number")
        return py::cast(item.exacts.number);
    else if (key == "pages")
        return py::cast(item.exacts.pages);

    /* Nonexact attributes */
    else if (key == "authors")
        return py::cast(item.exacts.volume);
    else if (key == "title")
        return py::cast(item.nonexacts.title);
    else if (key == "series")
        return py::cast(item.nonexacts.series);
    else if (key == "publisher")
        return py::cast(item.nonexacts.publisher);
    else if (key == "journal")
        return py::cast(item.nonexacts.journal);
    else if (key == "edition")
        return py::cast(item.nonexacts.edition);

    /* TODO: throw something that turns into an actual AttributeError in Python instead. */
    throw std::invalid_argument(std::string("AttributeError: no item attribute with key '") + key + "'");
}

PYBIND11_MODULE(pybookwyrm, m)
{
    m.attr("__doc__") = "bookwyrm python bindings";

    /* core::item bindings */

    m.attr("empty") = core::empty;

    py::enum_<core::year_mod>(m, "yearmod")
        .value("unused", core::year_mod::unused)
        .value("equal",  core::year_mod::equal)
        .value("eq_gt",  core::year_mod::eq_gt)
        .value("eq_lt",  core::year_mod::eq_lt)
        .value("lt",     core::year_mod::lt)
        .value("gt",     core::year_mod::gt);

    py::class_<core::item>(m, "item")
        .def("__getattr__", &getattr);

    /* core::plugin_handler bindings */

    py::enum_<core::log_level>(m, "log_level")
        .value("debug", core::log_level::debug)
        .value("info",  core::log_level::info)
        .value("warn",  core::log_level::warn)
        .value("error", core::log_level::err);

    py::class_<core::plugin_handler>(m, "bookwyrm")
        .def("feed",        &core::plugin_handler::add_item)
        .def("log",         &core::plugin_handler::log);
}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2014 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/libmesh_common.h"

#ifdef LIBMESH_HAVE_PETSC

// C++ includes

// Local Includes
#include "libmesh/petsc_preconditioner.h"
#include "libmesh/petsc_macro.h"
#include "libmesh/petsc_matrix.h"
#include "libmesh/petsc_vector.h"
#include "libmesh/libmesh_common.h"

// PCBJacobiGetSubKSP was defined in petscksp.h in PETSc 2.3.3, 3.1.0
#if PETSC_VERSION_LESS_THAN(3,1,0)

EXTERN_C_FOR_PETSC_BEGIN
#include "petscksp.h"
EXTERN_C_FOR_PETSC_END

#endif

namespace libMesh
{

template <typename T>
void PetscPreconditioner<T>::apply(const NumericVector<T> & x, NumericVector<T> & y)
{
  PetscVector<T> & x_pvec = cast_ref<PetscVector<T>&>(const_cast<NumericVector<T>&>(x));
  PetscVector<T> & y_pvec = cast_ref<PetscVector<T>&>(const_cast<NumericVector<T>&>(y));

  Vec x_vec = x_pvec.vec();
  Vec y_vec = y_pvec.vec();

  int ierr = PCApply(_pc,x_vec,y_vec);
  LIBMESH_CHKERRABORT(ierr);
}

template <typename T>
void PetscPreconditioner<T>::init ()
{
  if(!this->_matrix)
    libmesh_error_msg("ERROR: No matrix set for PetscPreconditioner, but init() called");

  // Clear the preconditioner in case it has been created in the past
  if (!this->_is_initialized)
    {
      // Should probably use PCReset(), but it's not working at the moment so we'll destroy instead
      if (_pc)
        {
          int ierr = LibMeshPCDestroy(&_pc);
          LIBMESH_CHKERRABORT(ierr);
        }

      int ierr = PCCreate(this->comm().get(),&_pc);
      LIBMESH_CHKERRABORT(ierr);

      PetscMatrix<T> * pmatrix = cast_ptr<PetscMatrix<T>*, SparseMatrix<T> >(this->_matrix);

      _mat = pmatrix->mat();
    }

#if PETSC_RELEASE_LESS_THAN(3,5,0)
  int ierr = PCSetOperators(_pc,_mat,_mat,SAME_NONZERO_PATTERN);
#else
  int ierr = PCSetOperators(_pc,_mat,_mat);
#endif
  LIBMESH_CHKERRABORT(ierr);

  // Set the PCType.  Note: this used to be done *before* the call to
  // PCSetOperators(), and only when !_is_initialized, but
  // 1.) Some preconditioners (those employing sub-preconditioners,
  // for example) have to call PCSetUp(), and can only do this after
  // the operators have been set.
  // 2.) It should be safe to call set_petsc_preconditioner_type()
  // multiple times.
  set_petsc_preconditioner_type(this->_preconditioner_type, _pc);

  this->_is_initialized = true;
}

template <typename T>
void PetscPreconditioner<T>::clear()
{
  if (_pc)
    {
      int ierr = LibMeshPCDestroy(&_pc);
      LIBMESH_CHKERRABORT(ierr);
    }
}

template <typename T>
void PetscPreconditioner<T>::set_petsc_preconditioner_type (const PreconditionerType & preconditioner_type, PC & pc)
{
  int ierr = 0;

  // get the communicator from the PETSc object
  Parallel::communicator comm;
  PetscObjectGetComm((PetscObject)pc, &comm);
  Parallel::Communicator communicator(comm);

  switch (preconditioner_type)
    {
    case IDENTITY_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCNONE));
      CHKERRABORT(comm,ierr);
      break;

    case CHOLESKY_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCCHOLESKY));
      CHKERRABORT(comm,ierr);
      break;

    case ICC_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCICC));
      CHKERRABORT(comm,ierr);
      break;

    case ILU_PRECOND:
      {
        // In serial, just set the ILU preconditioner type
        if (communicator.size())
          {
            ierr = PCSetType (pc, const_cast<KSPType>(PCILU));
            CHKERRABORT(comm,ierr);
          }
        else
          {
            // But PETSc has no truly parallel ILU, instead you have to set
            // an actual parallel preconditioner (e.g. block Jacobi) and then
            // assign ILU sub-preconditioners.
            ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
            CHKERRABORT(comm,ierr);

            // Set ILU as the sub preconditioner type
            set_petsc_subpreconditioner_type(PCILU, pc);
          }
        break;
      }

    case LU_PRECOND:
      {
        // In serial, just set the LU preconditioner type
        if (communicator.size())
          {
            ierr = PCSetType (pc, const_cast<KSPType>(PCLU));
            CHKERRABORT(comm,ierr);
          }
        else
          {
            // But PETSc has no truly parallel LU, instead you have to set
            // an actual parallel preconditioner (e.g. block Jacobi) and then
            // assign LU sub-preconditioners.
            ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
            CHKERRABORT(comm,ierr);

            // Set ILU as the sub preconditioner type
            set_petsc_subpreconditioner_type(PCLU, pc);
          }
        break;
      }

    case ASM_PRECOND:
      {
        // In parallel, I think ASM uses ILU by default as the sub-preconditioner...
        // I tried setting a different sub-preconditioner here, but apparently the matrix
        // is not in the correct state (at this point) to call PCSetUp().
        ierr = PCSetType (pc, const_cast<KSPType>(PCASM));
        CHKERRABORT(comm,ierr);
        break;
      }

    case JACOBI_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCJACOBI));
      CHKERRABORT(comm,ierr);
      break;

    case BLOCK_JACOBI_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
      CHKERRABORT(comm,ierr);
      break;

    case SOR_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCSOR));
      CHKERRABORT(comm,ierr);
      break;

    case EISENSTAT_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCEISENSTAT));
      CHKERRABORT(comm,ierr);
      break;

    case AMG_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCHYPRE));
      CHKERRABORT(comm,ierr);
      break;

#if !(PETSC_VERSION_LESS_THAN(2,1,2))
      // Only available for PETSC >= 2.1.2
    case USER_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCMAT));
      CHKERRABORT(comm,ierr);
      break;
#endif

    case SHELL_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCSHELL));
      CHKERRABORT(comm,ierr);
      break;

    default:
      libMesh::err << "ERROR:  Unsupported PETSC Preconditioner: "
                   << preconditioner_type       << std::endl
                   << "Continuing with PETSC defaults" << std::endl;
    }

  // Set additional options if we are doing AMG and
  // HYPRE is available
#ifdef LIBMESH_HAVE_PETSC_HYPRE
  if (preconditioner_type == AMG_PRECOND)
    {
      ierr = PCHYPRESetType(pc, "boomeramg");
      CHKERRABORT(comm,ierr);
    }
#endif

  // Let the commandline override stuff
  // FIXME: Unless we are doing AMG???
  if (preconditioner_type != AMG_PRECOND)
    {
      ierr = PCSetFromOptions(pc);
      CHKERRABORT(comm,ierr);
    }
}

template <typename T>
#if PETSC_VERSION_LESS_THAN(3,0,0)
void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(PCType type, PC& pc)
#else
  void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(const PCType type, PC& pc)
#endif
{
  // For catching PETSc error return codes
  int ierr = 0;

  // get the communicator from the PETSc object
  Parallel::communicator comm;
  PetscObjectGetComm((PetscObject)pc, &comm);
  Parallel::Communicator communicator(comm);

  // All docs say must call KSPSetUp or PCSetUp before calling PCBJacobiGetSubKSP.
  // You must call PCSetUp after the preconditioner operators have been set, otherwise you get the:
  //
  // "Object is in wrong state!"
  // "Matrix must be set first."
  //
  // error messages...
  ierr = PCSetUp(pc);
  CHKERRABORT(comm,ierr);

  // To store array of local KSP contexts on this processor
  KSP* subksps;

  // the number of blocks on this processor
  PetscInt n_local;

  // The global number of the first block on this processor.
  // This is not used, so we just pass PETSC_NULL instead.
  // int first_local;

  // Fill array of local KSP contexts
  ierr = PCBJacobiGetSubKSP(pc, &n_local, PETSC_NULL, &subksps);
  CHKERRABORT(comm,ierr);

  // Loop over sub-ksp objects, set ILU preconditioner
  for (PetscInt i=0; i<n_local; ++i)
    {
      // Get pointer to sub KSP object's PC
      PC subpc;
      ierr = KSPGetPC(subksps[i], &subpc);
      CHKERRABORT(comm,ierr);

      // Set requested type on the sub PC
      ierr = PCSetType(subpc, type);
      CHKERRABORT(comm,ierr);
    }

}

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

} // namespace libMesh

#endif // #ifdef LIBMESH_HAVE_PETSC
<commit_msg>For some reason, we were not calling PCSetFromOptions() when using Hypre preconditioners.<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2014 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/libmesh_common.h"

#ifdef LIBMESH_HAVE_PETSC

// C++ includes

// Local Includes
#include "libmesh/petsc_preconditioner.h"
#include "libmesh/petsc_macro.h"
#include "libmesh/petsc_matrix.h"
#include "libmesh/petsc_vector.h"
#include "libmesh/libmesh_common.h"

// PCBJacobiGetSubKSP was defined in petscksp.h in PETSc 2.3.3, 3.1.0
#if PETSC_VERSION_LESS_THAN(3,1,0)

EXTERN_C_FOR_PETSC_BEGIN
#include "petscksp.h"
EXTERN_C_FOR_PETSC_END

#endif

namespace libMesh
{

template <typename T>
void PetscPreconditioner<T>::apply(const NumericVector<T> & x, NumericVector<T> & y)
{
  PetscVector<T> & x_pvec = cast_ref<PetscVector<T>&>(const_cast<NumericVector<T>&>(x));
  PetscVector<T> & y_pvec = cast_ref<PetscVector<T>&>(const_cast<NumericVector<T>&>(y));

  Vec x_vec = x_pvec.vec();
  Vec y_vec = y_pvec.vec();

  int ierr = PCApply(_pc,x_vec,y_vec);
  LIBMESH_CHKERRABORT(ierr);
}

template <typename T>
void PetscPreconditioner<T>::init ()
{
  if(!this->_matrix)
    libmesh_error_msg("ERROR: No matrix set for PetscPreconditioner, but init() called");

  // Clear the preconditioner in case it has been created in the past
  if (!this->_is_initialized)
    {
      // Should probably use PCReset(), but it's not working at the moment so we'll destroy instead
      if (_pc)
        {
          int ierr = LibMeshPCDestroy(&_pc);
          LIBMESH_CHKERRABORT(ierr);
        }

      int ierr = PCCreate(this->comm().get(),&_pc);
      LIBMESH_CHKERRABORT(ierr);

      PetscMatrix<T> * pmatrix = cast_ptr<PetscMatrix<T>*, SparseMatrix<T> >(this->_matrix);

      _mat = pmatrix->mat();
    }

#if PETSC_RELEASE_LESS_THAN(3,5,0)
  int ierr = PCSetOperators(_pc,_mat,_mat,SAME_NONZERO_PATTERN);
#else
  int ierr = PCSetOperators(_pc,_mat,_mat);
#endif
  LIBMESH_CHKERRABORT(ierr);

  // Set the PCType.  Note: this used to be done *before* the call to
  // PCSetOperators(), and only when !_is_initialized, but
  // 1.) Some preconditioners (those employing sub-preconditioners,
  // for example) have to call PCSetUp(), and can only do this after
  // the operators have been set.
  // 2.) It should be safe to call set_petsc_preconditioner_type()
  // multiple times.
  set_petsc_preconditioner_type(this->_preconditioner_type, _pc);

  this->_is_initialized = true;
}

template <typename T>
void PetscPreconditioner<T>::clear()
{
  if (_pc)
    {
      int ierr = LibMeshPCDestroy(&_pc);
      LIBMESH_CHKERRABORT(ierr);
    }
}

template <typename T>
void PetscPreconditioner<T>::set_petsc_preconditioner_type (const PreconditionerType & preconditioner_type, PC & pc)
{
  int ierr = 0;

  // get the communicator from the PETSc object
  Parallel::communicator comm;
  PetscObjectGetComm((PetscObject)pc, &comm);
  Parallel::Communicator communicator(comm);

  switch (preconditioner_type)
    {
    case IDENTITY_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCNONE));
      CHKERRABORT(comm,ierr);
      break;

    case CHOLESKY_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCCHOLESKY));
      CHKERRABORT(comm,ierr);
      break;

    case ICC_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCICC));
      CHKERRABORT(comm,ierr);
      break;

    case ILU_PRECOND:
      {
        // In serial, just set the ILU preconditioner type
        if (communicator.size())
          {
            ierr = PCSetType (pc, const_cast<KSPType>(PCILU));
            CHKERRABORT(comm,ierr);
          }
        else
          {
            // But PETSc has no truly parallel ILU, instead you have to set
            // an actual parallel preconditioner (e.g. block Jacobi) and then
            // assign ILU sub-preconditioners.
            ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
            CHKERRABORT(comm,ierr);

            // Set ILU as the sub preconditioner type
            set_petsc_subpreconditioner_type(PCILU, pc);
          }
        break;
      }

    case LU_PRECOND:
      {
        // In serial, just set the LU preconditioner type
        if (communicator.size())
          {
            ierr = PCSetType (pc, const_cast<KSPType>(PCLU));
            CHKERRABORT(comm,ierr);
          }
        else
          {
            // But PETSc has no truly parallel LU, instead you have to set
            // an actual parallel preconditioner (e.g. block Jacobi) and then
            // assign LU sub-preconditioners.
            ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
            CHKERRABORT(comm,ierr);

            // Set ILU as the sub preconditioner type
            set_petsc_subpreconditioner_type(PCLU, pc);
          }
        break;
      }

    case ASM_PRECOND:
      {
        // In parallel, I think ASM uses ILU by default as the sub-preconditioner...
        // I tried setting a different sub-preconditioner here, but apparently the matrix
        // is not in the correct state (at this point) to call PCSetUp().
        ierr = PCSetType (pc, const_cast<KSPType>(PCASM));
        CHKERRABORT(comm,ierr);
        break;
      }

    case JACOBI_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCJACOBI));
      CHKERRABORT(comm,ierr);
      break;

    case BLOCK_JACOBI_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCBJACOBI));
      CHKERRABORT(comm,ierr);
      break;

    case SOR_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCSOR));
      CHKERRABORT(comm,ierr);
      break;

    case EISENSTAT_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCEISENSTAT));
      CHKERRABORT(comm,ierr);
      break;

    case AMG_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCHYPRE));
      CHKERRABORT(comm,ierr);
      break;

#if !(PETSC_VERSION_LESS_THAN(2,1,2))
      // Only available for PETSC >= 2.1.2
    case USER_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCMAT));
      CHKERRABORT(comm,ierr);
      break;
#endif

    case SHELL_PRECOND:
      ierr = PCSetType (pc, const_cast<KSPType>(PCSHELL));
      CHKERRABORT(comm,ierr);
      break;

    default:
      libMesh::err << "ERROR:  Unsupported PETSC Preconditioner: "
                   << preconditioner_type       << std::endl
                   << "Continuing with PETSC defaults" << std::endl;
    }

  // Set additional options if we are doing AMG and
  // HYPRE is available
#ifdef LIBMESH_HAVE_PETSC_HYPRE
  if (preconditioner_type == AMG_PRECOND)
    {
      ierr = PCHYPRESetType(pc, "boomeramg");
      CHKERRABORT(comm,ierr);
    }
#endif

  // Let the commandline override stuff
  ierr = PCSetFromOptions(pc);
  CHKERRABORT(comm,ierr);
}

template <typename T>
#if PETSC_VERSION_LESS_THAN(3,0,0)
void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(PCType type, PC& pc)
#else
  void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(const PCType type, PC& pc)
#endif
{
  // For catching PETSc error return codes
  int ierr = 0;

  // get the communicator from the PETSc object
  Parallel::communicator comm;
  PetscObjectGetComm((PetscObject)pc, &comm);
  Parallel::Communicator communicator(comm);

  // All docs say must call KSPSetUp or PCSetUp before calling PCBJacobiGetSubKSP.
  // You must call PCSetUp after the preconditioner operators have been set, otherwise you get the:
  //
  // "Object is in wrong state!"
  // "Matrix must be set first."
  //
  // error messages...
  ierr = PCSetUp(pc);
  CHKERRABORT(comm,ierr);

  // To store array of local KSP contexts on this processor
  KSP* subksps;

  // the number of blocks on this processor
  PetscInt n_local;

  // The global number of the first block on this processor.
  // This is not used, so we just pass PETSC_NULL instead.
  // int first_local;

  // Fill array of local KSP contexts
  ierr = PCBJacobiGetSubKSP(pc, &n_local, PETSC_NULL, &subksps);
  CHKERRABORT(comm,ierr);

  // Loop over sub-ksp objects, set ILU preconditioner
  for (PetscInt i=0; i<n_local; ++i)
    {
      // Get pointer to sub KSP object's PC
      PC subpc;
      ierr = KSPGetPC(subksps[i], &subpc);
      CHKERRABORT(comm,ierr);

      // Set requested type on the sub PC
      ierr = PCSetType(subpc, type);
      CHKERRABORT(comm,ierr);
    }

}

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

} // namespace libMesh

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