/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**
** Copyright (C), 2004, Victorian Partnership for Advanced Computing (VPAC) Ltd, 110 Victoria Street, Melbourne, 3053, Australia.
**
** Authors:
**	Ogar R. Widjaja, Computational Scientist, VPAC.
**	Raquibul Hassan, Software Engineer, VPAC. (raq@vpac.org)
**	Keith Hsuan, Computational Scientist, VPAC (keith@vpac.org)
**	William F. Appelbe, Director, VPAC. (bill@vpac.org)
**	Stevan M. Quenette, Senior Software Engineer, VPAC. (steve@vpac.org)
**	Patrick D. Sunter, Software Engineer, VPAC. (patrick@vpac.org)
**
** This file may be distributed under the terms of the VPAC Public License
** as defined by VPAC of Australia and appearing in the file
** LICENSE.VPL included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** $Id: Erosion.c 225 2005-12-22 00:01:19Z AlanLo $
**
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/


#include <mpi.h>
#include <StGermain/StGermain.h>
#include "SPModel/SPModel.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "FluvialErosionVariant.h"

/* Textual name of this module */
const Type SPModelFluvialErosionVariant_Type = "SPModelFluvialErosionVariant";

ExtensionInfo_Index SPModel_Simulation_ContextExtHandle;
ExtensionInfo_Index SPModel_FluvialErosionVariant_ContextExtHandle;

void* _SPModelFluvialErosionVariant_DefaultNew( Name name ) {
	return Codelet_New(
			SPModelFluvialErosionVariant_Type,
			_SPModelFluvialErosionVariant_DefaultNew,
			_SPModelFluvialErosionVariant_Construct,
			_Codelet_Build,
			_Codelet_Initialise,
			_Codelet_Execute,
			_Codelet_Destroy,
			name );
}

void _SPModelFluvialErosionVariant_Construct( void* component, Stg_ComponentFactory* data ) {	
	SPModel_Context*				context;
	
	context = (SPModel_Context*)Stg_ComponentFactory_ConstructByName( data, "context", SPModel_Context, True );
	
	SPModel_FluvialErosionVariant_ContextExtHandle = ExtensionManager_Add( context->extensionMgr, "FluvialErosionVariant",
											sizeof(SPModelFluvialErosionVariantContextExtension) );
	_SPModelFluvialErosionVariant_Init( context );
	
	Journal_DPrintf( context->debug, "In %s():\n", __func__ );
	ContextEP_Append( context, AbstractContext_EP_Solve, SPModelFluvialErosionVariant_Solve );
}

void _SPModelFluvialErosionVariant_Init( void* _context ) {
	SPModel_Context *context = (SPModel_Context*)_context;
	SPModelFluvialErosionVariantContextExtension	*fluvialErosionVariantExt = NULL;
	
	assert( context );
	
	SPModel_Simulation_ContextExtHandle = ExtensionManager_GetHandle( context->extensionMgr, "Simulation" );
	
	fluvialErosionVariantExt = (SPModelFluvialErosionVariantContextExtension*)ExtensionManager_Get
				( context->extensionMgr, context, SPModel_FluvialErosionVariant_ContextExtHandle );
	assert( fluvialErosionVariantExt );

	fluvialErosionVariantExt->fluxPower = Dictionary_GetFloat_WithDefault( context->dictionary, "fluxPower", 1.0f );
	fluvialErosionVariantExt->gradientPower = Dictionary_GetFloat_WithDefault( context->dictionary, "gradientPower", 1.0f );
}

void SPModelFluvialErosionVariant_BoundaryConditions( void *_context )
{
	int i = 0;
	SPModel_Context *context = NULL;
	SPModelSimulationContextExtension *simulationExt = NULL;
	SurfaceMesh *mesh;

	context = (SPModel_Context*)_context;
	assert( context );
	
	simulationExt = (SPModelSimulationContextExtension*)ExtensionManager_Get
				( context->extensionMgr, context, SPModel_Simulation_ContextExtHandle );
	assert( simulationExt );
	
	mesh = context->localMesh;
	
	for( i=0; i<mesh->myLoad; i++ ){
		if( (mesh->boundaryConditions[mesh->id[i]-1]) == 0 ){
			mesh->h[i] -= simulationExt->sedimentHistory[i];
			simulationExt->sedimentHistory[i] = 0.0f;
			simulationExt->sediment[i] = 0.0f;
		}
	}	
}

float transportEquation( SPModel_Context *context, int localIndex, SurfaceMesh *mesh, SPModelSimulationContextExtension *simulationExt )
{
	SPModelFluvialErosionVariantContextExtension	*fluvialErosionVariantExt = NULL;
	float slope = 0.0f; 

	assert( simulationExt );
	assert( mesh );
	assert( context );
	
	fluvialErosionVariantExt = (SPModelFluvialErosionVariantContextExtension*)ExtensionManager_Get
				( context->extensionMgr, context, SPModel_FluvialErosionVariant_ContextExtHandle );
	assert( fluvialErosionVariantExt );
	
	slope = -mesh->slope[localIndex];
	
	return powf( simulationExt->water[localIndex] * mesh->surface[localIndex], fluvialErosionVariantExt->fluxPower ) * 
			powf( slope, fluvialErosionVariantExt->gradientPower ) *
			context->fluvialConstant;
}

void SPModelFluvialErosionVariant_Solve( void *_context )
{
	SPModel_Context *context = NULL;
	SPModelSimulationContextExtension *simulationExt = NULL;
 
	context = (SPModel_Context*)_context;
	assert( context );
	
	simulationExt = (SPModelSimulationContextExtension*)ExtensionManager_Get
				( context->extensionMgr, context, SPModel_Simulation_ContextExtHandle );
	assert( simulationExt );

	SPModelFluvialErosionVariant_BoundaryConditions( _context );

	fluvial( context, simulationExt, transportEquation );
}

Index SPModelFluvialErosionVariant_Register( PluginsManager* pluginsManager )
{
	return PluginsManager_Submit( pluginsManager, SPModelFluvialErosionVariant_Type, "0", _SPModelFluvialErosionVariant_DefaultNew );
}