SIM/SIM_GasAdd.C

/*
 * Copyright (c) 2013
 *      Side Effects Software Inc.  All rights reserved.
 *
 * Redistribution and use of Houdini Development Kit samples in source and
 * binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. The name of Side Effects Software may not be used to endorse or
 *    promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `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 SIDE EFFECTS SOFTWARE 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 "SIM_GasAdd.h"
#include <UT/UT_DSOVersion.h>
#include <UT/UT_Interrupt.h>
#include <PRM/PRM_Include.h>
#include <SIM/SIM_PRMShared.h>
#include <SIM/SIM_DopDescription.h>
#include <SIM/SIM_ScalarField.h>
#include <SIM/SIM_VectorField.h>
#include <SIM/SIM_MatrixField.h>
#include <SIM/SIM_Object.h>
#include <GAS/GAS_SubSolver.h>

using namespace HDK_Sample;

///
/// This is the hook that Houdini grabs from the dll to link in
/// this.  As such, it merely has to implement the data factory
/// for this node.
///
void
initializeSIM(void *)
{
    IMPLEMENT_DATAFACTORY(SIM_GasAdd);
}

/// Standard constructor, note that BaseClass was crated by the
/// DECLARE_DATAFACTORY and provides an easy way to chain through
/// the class hierarchy.
SIM_GasAdd::SIM_GasAdd(const SIM_DataFactory *factory)
    : BaseClass(factory)
{
}

SIM_GasAdd::~SIM_GasAdd()
{
}

/// Used to automatically populate the node which will represent
/// this data type.
const SIM_DopDescription *
SIM_GasAdd::getDopDescription()
{
    static PRM_Name     theDstFieldName(GAS_NAME_FIELDDEST, "Dest Field");
    static PRM_Name     theSrcFieldName(GAS_NAME_FIELDSOURCE, "Source Field");

    static PRM_Template          theTemplates[] = {
        PRM_Template(PRM_STRING, 1, &theDstFieldName),
        PRM_Template(PRM_STRING, 1, &theSrcFieldName),
        PRM_Template()
    };

    static SIM_DopDescription    theDopDescription(
            true,               // Should we make a DOP?
            "hdk_gasadd",       // Internal name of the DOP.
            "Gas Add",          // Label of the DOP
            "Solver",           // Default data name
            classname(),        // The type of this DOP, usually the class.
            theTemplates);      // Template list for generating the DOP

    return &theDopDescription;
}

bool
SIM_GasAdd::solveGasSubclass(SIM_Engine &engine,
                        SIM_Object *obj,
                        SIM_Time time,
                        SIM_Time timestep)
{
    SIM_ScalarField     *srcscalar, *dstscalar;
    SIM_VectorField     *srcvector, *dstvector;
    SIM_MatrixField     *srcmatrix, *dstmatrix;

    SIM_DataArray        src, dst;
    int                  i, j, k;

    getMatchingData(src, obj, GAS_NAME_FIELDSOURCE);
    getMatchingData(dst, obj, GAS_NAME_FIELDDEST);

    // Now for each pair of source and dst fields, we want to add
    // src to dst.  We want to support scalar, vector, and matrix fields,
    // but only compatible operations.  We can determine what type we
    // have via casting.
    for (i = 0; i < dst.entries(); i++)
    {
        // Check to see if we exceeded our src list.
        if (i >= src.entries())
        {
            addError(obj, SIM_MESSAGE, "Fewer source fields than destination fields.", UT_ERROR_WARNING);
            break;
        }

        // Try each casting option.
        dstscalar = SIM_DATA_CAST(dst(i), SIM_ScalarField);
        srcscalar = SIM_DATA_CAST(src(i), SIM_ScalarField);

        dstvector = SIM_DATA_CAST(dst(i), SIM_VectorField);
        srcvector = SIM_DATA_CAST(src(i), SIM_VectorField);

        dstmatrix = SIM_DATA_CAST(dst(i), SIM_MatrixField);
        srcmatrix = SIM_DATA_CAST(src(i), SIM_MatrixField);

        if (dstscalar && srcscalar)
        {
            addFields(dstscalar->getField(), srcscalar->getField());
        }

        if (dstvector && srcvector)
        {
            for (j = 0; j < 3; j++)
                addFields(dstvector->getField(j), srcvector->getField(j));
        }

        if (dstmatrix && srcmatrix)
        {
            for (j = 0; j < 3; j++)
                for (k = 0; k < 3; k++)
                    addFields(dstmatrix->getField(j, k), srcmatrix->getField(j, k));
        }

        // Make sure we are flagged as dirty
        if (dstscalar)
            dstscalar->pubHandleModification();
        if (dstvector)
            dstvector->pubHandleModification();
        if (dstmatrix)
            dstmatrix->pubHandleModification();
    }

    // Successful cook
    return true;
}

void
SIM_GasAdd::addFieldsPartial(SIM_RawField *dst, const SIM_RawField *src, const UT_JobInfo &info)
{
    UT_VoxelArrayIteratorF      vit;
    UT_Interrupt                *boss = UTgetInterrupt();

    // Initialize our iterator to run over our destination field.
    vit.setArray(dst->field());

    // When we complete each tile the tile is tested to see if it can be
    // compressed, ie, is now constant.  If so, it is compressed.
    vit.setCompressOnExit(true);

    // Restrict our iterator only over part of the range.  Using the
    // info parameters means each thread gets its own subregion.
    vit.setPartialRange(info.job(), info.numJobs());

    // Check if we are aligned.  If we are aligned, we have a precise
    // 1:1 mapping of our voxels so we don't need to do any lookups
    // from world space, which is much faster.
    if (dst->isAligned(src))
    {
        UT_VoxelProbeF          probe;

        probe.setArray(src->field());
                
        for (vit.rewind(); !vit.atEnd(); vit.advance())
        {
            if (vit.isStartOfTile() && boss->opInterrupt())
                break;

            // Update our read probe to match our current iterator
            // position
            probe.setIndex(vit);

            // Write out the sum of the two fields.
            // Instead of using the iterator, we could also
            // have built a UT_VoxelRWProbeF.
            vit.setValue( vit.getValue() + probe.getValue() );
        }
    }
    else
    {
        // We need to lookup the world space position of our voxel so we can
        // find it in our destination.
        UT_Vector3              pos;

        for (vit.rewind(); !vit.atEnd(); vit.advance())
        {
            if (vit.isStartOfTile() && boss->opInterrupt())
                break;
            dst->indexToPos(vit.x(), vit.y(), vit.z(), pos);

            // Read the source field with trilinear interpolation
            // according to our world space position, this allows
            // us to thus work with misaligned fields.
            vit.setValue( vit.getValue() + src->getValue(pos) );
        }
    }
}

Generated on Mon Jan 28 00:26:19 2013 for HDK by  doxygen 1.5.9