HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SIM_GasAdd.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018
3  * Side Effects Software Inc. All rights reserved.
4  *
5  * Redistribution and use of Houdini Development Kit samples in source and
6  * binary forms, with or without modification, are permitted provided that the
7  * following conditions are met:
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. The name of Side Effects Software may not be used to endorse or
11  * promote products derived from this software without specific prior
12  * written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *----------------------------------------------------------------------------
26  */
27 
28 #include "SIM_GasAdd.h"
29 #include <UT/UT_DSOVersion.h>
30 #include <UT/UT_Interrupt.h>
31 #include <PRM/PRM_Include.h>
32 #include <SIM/SIM_PRMShared.h>
33 #include <SIM/SIM_DopDescription.h>
34 #include <SIM/SIM_ScalarField.h>
35 #include <SIM/SIM_VectorField.h>
36 #include <SIM/SIM_MatrixField.h>
37 #include <SIM/SIM_Object.h>
38 #include <GAS/GAS_SubSolver.h>
39 
40 using namespace HDK_Sample;
41 
42 ///
43 /// This is the hook that Houdini grabs from the dll to link in
44 /// this. As such, it merely has to implement the data factory
45 /// for this node.
46 ///
47 void
49 {
51 }
52 
53 /// Standard constructor, note that BaseClass was crated by the
54 /// DECLARE_DATAFACTORY and provides an easy way to chain through
55 /// the class hierarchy.
57  : BaseClass(factory)
58 {
59 }
60 
62 {
63 }
64 
65 /// Used to automatically populate the node which will represent
66 /// this data type.
67 const SIM_DopDescription *
68 SIM_GasAdd::getDopDescription()
69 {
70  static PRM_Name theDstFieldName(GAS_NAME_FIELDDEST, "Dest Field");
71  static PRM_Name theSrcFieldName(GAS_NAME_FIELDSOURCE, "Source Field");
72 
73  static PRM_Template theTemplates[] = {
74  PRM_Template(PRM_STRING, 1, &theDstFieldName),
75  PRM_Template(PRM_STRING, 1, &theSrcFieldName),
76  PRM_Template()
77  };
78 
79  static SIM_DopDescription theDopDescription(
80  true, // Should we make a DOP?
81  "hdk_gasadd", // Internal name of the DOP.
82  "Gas Add", // Label of the DOP
83  "Solver", // Default data name
84  classname(), // The type of this DOP, usually the class.
85  theTemplates); // Template list for generating the DOP
86 
87  return &theDopDescription;
88 }
89 
90 bool
92  SIM_Object *obj,
93  SIM_Time time,
94  SIM_Time timestep)
95 {
96  SIM_ScalarField *srcscalar, *dstscalar;
97  SIM_VectorField *srcvector, *dstvector;
98  SIM_MatrixField *srcmatrix, *dstmatrix;
99 
101  int i, j, k;
102 
105 
106  // Now for each pair of source and dst fields, we want to add
107  // src to dst. We want to support scalar, vector, and matrix fields,
108  // but only compatible operations. We can determine what type we
109  // have via casting.
110  for (i = 0; i < dst.entries(); i++)
111  {
112  // Check to see if we exceeded our src list.
113  if (i >= src.entries())
114  {
115  addError(obj, SIM_MESSAGE, "Fewer source fields than destination fields.", UT_ERROR_WARNING);
116  break;
117  }
118 
119  // Try each casting option.
120  dstscalar = SIM_DATA_CAST(dst(i), SIM_ScalarField);
121  srcscalar = SIM_DATA_CAST(src(i), SIM_ScalarField);
122 
123  dstvector = SIM_DATA_CAST(dst(i), SIM_VectorField);
124  srcvector = SIM_DATA_CAST(src(i), SIM_VectorField);
125 
126  dstmatrix = SIM_DATA_CAST(dst(i), SIM_MatrixField);
127  srcmatrix = SIM_DATA_CAST(src(i), SIM_MatrixField);
128 
129  if (dstscalar && srcscalar)
130  {
131  addFields(dstscalar->getField(), srcscalar->getField());
132  }
133 
134  if (dstvector && srcvector)
135  {
136  for (j = 0; j < 3; j++)
137  addFields(dstvector->getField(j), srcvector->getField(j));
138  }
139 
140  if (dstmatrix && srcmatrix)
141  {
142  for (j = 0; j < 3; j++)
143  for (k = 0; k < 3; k++)
144  addFields(dstmatrix->getField(j, k), srcmatrix->getField(j, k));
145  }
146 
147  // Make sure we are flagged as dirty
148  if (dstscalar)
149  dstscalar->pubHandleModification();
150  if (dstvector)
151  dstvector->pubHandleModification();
152  if (dstmatrix)
153  dstmatrix->pubHandleModification();
154  }
155 
156  // Successful cook
157  return true;
158 }
159 
160 void
162 {
164  UT_Interrupt *boss = UTgetInterrupt();
165 
166  // Initialize our iterator to run over our destination field.
167  vit.setArray(dst->fieldNC());
168 
169  // When we complete each tile the tile is tested to see if it can be
170  // compressed, ie, is now constant. If so, it is compressed.
171  vit.setCompressOnExit(true);
172 
173  // Restrict our iterator only over part of the range. Using the
174  // info parameters means each thread gets its own subregion.
175  vit.setPartialRange(info.job(), info.numJobs());
176 
177  // Check if we are aligned. If we are aligned, we have a precise
178  // 1:1 mapping of our voxels so we don't need to do any lookups
179  // from world space, which is much faster.
180  if (dst->isAligned(src))
181  {
182  UT_VoxelProbeF probe;
183 
184  probe.setConstArray(src->field());
185 
186  for (vit.rewind(); !vit.atEnd(); vit.advance())
187  {
188  if (vit.isStartOfTile() && boss->opInterrupt())
189  break;
190 
191  // Update our read probe to match our current iterator
192  // position
193  probe.setIndex(vit);
194 
195  // Write out the sum of the two fields.
196  // Instead of using the iterator, we could also
197  // have built a UT_VoxelRWProbeF.
198  vit.setValue( vit.getValue() + probe.getValue() );
199  }
200  }
201  else
202  {
203  // We need to lookup the world space position of our voxel so we can
204  // find it in our destination.
205  UT_Vector3 pos;
206 
207  for (vit.rewind(); !vit.atEnd(); vit.advance())
208  {
209  if (vit.isStartOfTile() && boss->opInterrupt())
210  break;
211  dst->indexToPos(vit.x(), vit.y(), vit.z(), pos);
212 
213  // Read the source field with trilinear interpolation
214  // according to our world space position, this allows
215  // us to thus work with misaligned fields.
216  vit.setValue( vit.getValue() + src->getValue(pos) );
217  }
218  }
219 }
int x() const
Retrieve the current location of the iterator.
SIM_RawField * getField(int axis) const
Retrieve raw field.
void pubHandleModification()
Signals to the field that it has been altered externally.
bool atEnd() const
Returns true if we have iterated over all of the voxels.
PRM_API const PRM_Type PRM_STRING
#define IMPLEMENT_DATAFACTORY(DataClass)
Definition: SIM_DataUtils.h:97
GT_API const UT_StringHolder time
void setValue(T t) const
Sets the voxel we are currently pointing to the given value.
UT_VoxelArrayF * fieldNC() const
Definition: SIM_RawField.h:488
SIM_RawField * getField(int i, int j) const
Retrieve raw field.
fpreal getValue(UT_Vector3 pos) const
Functions to resolve quantities about the field.
bool isStartOfTile() const
Returns true if we are at the start of a new tile.
void setArray(UT_VoxelArray< T > *vox)
SIM_GasAdd(const SIM_DataFactory *factory)
Definition: SIM_GasAdd.C:56
png_uint_32 i
Definition: png.h:2877
virtual bool solveGasSubclass(SIM_Engine &engine, SIM_Object *obj, SIM_Time time, SIM_Time timestep)
Definition: SIM_GasAdd.C:91
void getMatchingData(SIM_DataArray &data, SIM_Object *obj, const char *name, bool silent=false)
void pubHandleModification()
int opInterrupt(int percent=-1)
void setPartialRange(int idx, int numranges)
void pubHandleModification()
void rewind()
Resets the iterator to point to the first voxel.
T getValue() const
#define GAS_NAME_FIELDSOURCE
Definition: GAS_Utils.h:27
#define GAS_NAME_FIELDDEST
Definition: GAS_Utils.h:26
void addError(const SIM_RootData *root, int errorcode, const char *errorparm, UT_ErrorSeverity severity) const
Adds an error to our SIM_Engine.
void setCompressOnExit(bool shouldcompress)
bool setIndex(UT_VoxelArrayIterator< S > &vit)
This class holds a three dimensional tensor field.
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:453
void setConstArray(const UT_VoxelArray< T > *vox, int prex=0, int postx=0)
GLenum GLenum dst
Definition: glcorearb.h:1792
int numJobs() const
UT_API UT_Interrupt * UTgetInterrupt()
Obtain global UT_Interrupt singleton.
This class holds a three dimensional scalar field.
bool isAligned(const SIM_RawField *field) const
bool indexToPos(int x, int y, int z, UT_Vector3 &pos) const
#define SIM_DATA_CAST(Data, DataClass)
Definition: SIM_Utils.h:28
void initializeSIM(void *)
Definition: SIM_GasAdd.C:48
SIM_RawField * getField() const
Retrieve raw field.
This class holds a three dimensional vector field.
UT_VoxelArrayF UT_VoxelArrayF & field
void addFieldsPartial(SIM_RawField *dst, const SIM_RawField *src, const UT_JobInfo &info)
Definition: SIM_GasAdd.C:161
int job() const
void advance()
Advances the iterator to point to the next voxel.
GLenum src
Definition: glcorearb.h:1792