Commit 1b5d1681 authored by Matthieu Constant's avatar Matthieu Constant
Browse files

Merge branch 'master' of git.immc.ucl.ac.be:fluidparticles/marblesbag

parents 5c320973 1b6b33a2
......@@ -45,6 +45,9 @@ class fluid_problem :
def export(self, output_dir, t, it) :
lib.fluid_problem_export(self._fp, output_dir.encode(), c_double(t), c_int(it))
def export_vtk(self, output_dir, t, it) :
lib.fluid_problem_export_vtk(self._fp, output_dir.encode(), c_double(t), c_int(it))
def compute_node_force(self, dt) :
forces = numpy.ndarray([self.n_particles,2],"d",order="C")
lib.fluid_problem_compute_node_particle_force(self._fp, c_double(dt), c_void_p(forces.ctypes.data))
......
......@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <float.h>
#include <string.h>
#include <time.h>
typedef struct _Particle Particle;
typedef struct _Contact Contact;
......@@ -525,8 +526,124 @@ void ParticleToMesh(size_t nParticles, double *particles, int nElements, double
cellFree(tree);
}
int listcmp(const void *i0, const void *i1) {
const u_int32_t j0 = *(u_int32_t*)i0, j1 = *(u_int32_t*)i1;
return j0 - j1;
}
static int intersect(const double *amin, const double *amax, const double *bmin, const double *bmax) {
if (amin[0] > bmax[0] || amax[0] < bmin[0]) return 0;
if (amin[1] > bmax[1] || amax[1] < bmin[1]) return 0;
#if DIMENSION == 3
if (amin[2] > bmax[2] || amax[2] < bmin[2]) return 0;
#endif
return 1;
}
static void _particleProblemGenContacts2(ParticleProblem *p, const double alert)
{
clock_t tic = clock();
u_int32_t *list = NULL;
double bbmin[DIMENSION], bbmax[DIMENSION];
_particleProblemBoundingBox(p,bbmin,bbmax);
addAlert(alert,bbmin, bbmax);
u_int16_t N[DIMENSION];
double delta = alert*6;
for (int i = 0; i < DIMENSION; ++i) {
N[i] = (bbmax[i]-bbmin[i])/delta;
}
for (size_t i = 0; i < vectorSize(p->particles); ++i) {
double amin[DIMENSION], amax[DIMENSION];
particleBoundingBox(&p->particles[i], &p->position[i*DIMENSION],amin,amax);
addAlert(alert/2,amin,amax);
u_int16_t from[DIMENSION],to[DIMENSION];
for (int i = 0; i < DIMENSION; ++i){
from[i] = (amin[i]-bbmin[i])/delta;
to[i] = (amax[i]-bbmin[i])/delta;
}
#if DIMENSION == 2
for (int j = from[0]; j <= to[0]; ++j) {
for (int k = from[1]; k <= to[1]; ++k) {
u_int32_t bid = j*N[1]+k;
*vectorPush(&list) = bid;
*vectorPush(&list) = i;
}
}
#else
for (int j = from[0]; j <= to[0]; ++j) {
for (int k = from[1]; k <= to[1]; ++k) {
for (int l = from[2]; l <= to[2]; ++l) {
u_int32_t bid = (j*N[1]+k)*N[2]+l;
*vectorPush(&list) = bid;
*vectorPush(&list) = i;
}
}
}
#endif
}
clock_t tic1 = clock();
qsort(list, vectorSize(list)/2, 2*sizeof(u_int32_t), listcmp);
clock_t tic2 = clock();
int ntot = 0;
Contact *cc=NULL;
vectorPushN(&cc, 10000000);
vectorClear(cc);
double amin[DIMENSION], amax[DIMENSION];
double bmin[DIMENSION], bmax[DIMENSION];
for (int start = 0; start < vectorSize(list);) {
int end = start;
for (; end< vectorSize(list);end+=2) {
if (list[end] != list[start])
break;
}
for (int i = start; i < end; i+= 2) {
int ii = list[i+1];
Particle *p0 = &p->particles[ii];
double *x_i = &p->position[ii*DIMENSION];
for (int j = i; j < end; j+= 2) {
int jj = list[j+1];
Particle *p1 = &p->particles[jj];
double *x_j = &p->position[jj*DIMENSION];
Contact c;
c.dv = 0;
c.o0 = ii; c.o1 = jj;
double nnorm = 0;
for (int k = 0; k < DIMENSION; ++k) {
c.n[k] = x_i[k] - x_j[k];
nnorm += c.n[k]*c.n[k];
}
double dd =p0->r+p1->r+alert;
if (nnorm > dd*dd)
continue;
nnorm = sqrt(nnorm);
for (int i = 0; i < DIMENSION; ++i)
c.n[i] /= -nnorm;
c.D = fmax(0., nnorm - (p0->r + p1->r));
c.a0 = p1->m / (p0->m + p1->m);
c.a1 = p0->m / (p0->m + p1->m);
c.type = PARTICLE_PARTICLE;
ntot++;
*vectorPush(&cc) = c;
/*else if ((cold = findContactSorted(c, oldContacts, &iold))) {
coordAdd(&p->velocity[c->o0 * DIMENSION], -cold->dv * c->a0, c->n);
coordAdd(&p->velocity[c->o1 * DIMENSION], cold->dv * c->a1, c->n);
c->dv = cold->dv;
}*/
}
}
start = end;
}
clock_t tic3 = clock();
printf("time new %i : %i %i %i\n", tic3-tic, tic3-tic2,tic2-tic1, tic1-tic);
printf("%i / %i (%i%%)\n", vectorSize(cc), ntot, vectorSize(cc)*100/ntot);
vectorFree(cc);
}
static void _particleProblemGenContacts(ParticleProblem *p, const double alert)
{
//_particleProblemGenContacts2(p,alert);
clock_t tic = clock();
size_t iold = 0;
double bbmin[DIMENSION], bbmax[DIMENSION];
_particleProblemBoundingBox(p, bbmin, bbmax);
......@@ -538,12 +655,14 @@ static void _particleProblemGenContacts(ParticleProblem *p, const double alert)
// Particles
Contact *oldContacts = vectorDup(p->contacts), *cold;
vectorClear(p->contacts);
int ntot = 0;
for (size_t i = 0; i < vectorSize(p->particles); ++i) {
particleBoundingBox(&p->particles[i], &p->position[i * DIMENSION], amin, amax);
addAlert(alert/2, amin, amax);
vectorClear(found);
cellAdd(tree, amin, amax, i, &found);
for (size_t j = 0; j < vectorSize(found); ++j) {
ntot++;
Contact *c= vectorPush(&p->contacts);
if(!particleInitContact(i, &p->particles[i], &p->position[i * DIMENSION], found[j], &p->particles[found[j]], &p->position[found[j] * DIMENSION], alert, c))
vectorPop(p->contacts);
......@@ -554,6 +673,8 @@ static void _particleProblemGenContacts(ParticleProblem *p, const double alert)
}
}
}
printf("time old %i\n", clock()-tic);
//exit(0);
// Disks
for (size_t i = 0; i < vectorSize(p->disks); ++i) {
diskBoundingBox(&p->disks[i], amin, amax);
......@@ -838,11 +959,20 @@ void particleProblemWrite(const ParticleProblem *p, const char *filename) {
fclose(output);
}
void particleProblemWriteVtk(ParticleProblem *p, const char *filename) {
int particleProblemWriteVtk(ParticleProblem *p, const char *filename) {
FILE *f = fopen(filename, "w");
fprintf(f, "<VTKFile type=\"PolyData\">\n");
fprintf(f, "<PolyData>\n");
fprintf(f, "<Piece NumberOfPoints=\"%lu\">\n", vectorSize(p->particles));
if (!f){
printf("cannot open file %s\n", filename);
return -1;
}
size_t n_pp_contacts = 0;
for (size_t i = 0; i < vectorSize(p->contacts); ++i) {
if (p->contacts[i].type == PARTICLE_PARTICLE)
n_pp_contacts ++;
}
fprintf(f, "<VTKFile type=\"UnstructuredGrid\">\n");
fprintf(f, "<UnstructuredGrid>\n");
fprintf(f, "<Piece NumberOfPoints=\"%lu\" NumberOfCells=\"%lu\">\n", vectorSize(p->particles), n_pp_contacts);
fprintf(f, "<PointData Scalars=\"Radius\" Vectors=\"Velocity\">\n");
fprintf(f, "<DataArray Name=\"Radius\" NumberOfComponents = \"1\" type=\"Float32\" format=\"ascii\">\n");
for (size_t i = 0; i < vectorSize(p->particles); ++i) {
......@@ -867,17 +997,46 @@ void particleProblemWriteVtk(ParticleProblem *p, const char *filename) {
fprintf(f, "%.16g %.16g %.16g ", p->position[i * 3], p->position[i * 3 + 1], p->position[i * 3 + 2]);
#endif
}
fprintf(f, "\n</DataArray>\n</Points>\n");
fprintf(f, "\n</DataArray>\n");
fprintf(f, "</Points>\n");
fprintf(f, "<Cells>\n");
fprintf(f, "<DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">\n");
for (size_t i = 0; i < vectorSize(p->contacts); ++i) {
if (p->contacts[i].type == PARTICLE_PARTICLE) {
fprintf(f, "%i %i ", p->contacts[i].o0, p->contacts[i].o1);
}
}
fprintf(f, "\n</DataArray>\n");
fprintf(f, "<DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">\n");
for (size_t i = 0; i < n_pp_contacts; ++i) {
fprintf(f, "%i ", (i+1)*2);
}
fprintf(f, "\n</DataArray>\n");
fprintf(f, "<DataArray type=\"Int32\" Name=\"types\" format=\"ascii\">\n");
for (size_t i = 0; i < n_pp_contacts; ++i) {
fprintf(f, "3 ");
}
fprintf(f, "\n</DataArray>\n");
fprintf(f, "</Cells>\n");
fprintf(f, "<CellData Scalars=\"Reaction\">\n");
fprintf(f, "<DataArray Name=\"Reaction\" NumberOfComponents = \"1\" type=\"Float32\" format=\"ascii\">\n");
for (size_t i = 0; i < vectorSize(p->contacts); ++i) {
if (p->contacts[i].type == PARTICLE_PARTICLE) {
fprintf(f, "%g ", p->contacts[i].dv);
}
}
fprintf(f, "\n</DataArray>\n");
fprintf(f, "</CellData>\n");
fprintf(f, "</Piece>\n");
fprintf(f, "</PolyData>\n");
fprintf(f, "</UnstructuredGrid>\n");
fprintf(f, "</VTKFile>\n");
fclose(f);
}
void particleProblemWriteBoundaryVtk(ParticleProblem *p, const char *filename) {
FILE *f = fopen(filename, "w");
fprintf(f, "<VTKFile type=\"PolyData\">\n");
fprintf(f, "<PolyData>\n");
fprintf(f, "<VTKFile type=\"UnstructuredGrid\">\n");
fprintf(f, "<UnstructuredGrid>\n");
fprintf(f, "<Piece NumberOfPoints=\"%lu\" NumberOfLines=\"%lu\">\n", vectorSize(p->segments)*2, vectorSize(p->segments));
fprintf(f, "<Points>\n<DataArray NumberOfComponents=\"3\" type=\"Float32\" format=\"ascii\">\n");
for (size_t i = 0; i < vectorSize(p->segments); ++i) {
......@@ -925,7 +1084,7 @@ void particleProblemWriteBoundaryVtk(ParticleProblem *p, const char *filename) {
fprintf(f, "</Polys>\n");
fprintf(f, "</Piece>\n");
#endif
fprintf(f, "</PolyData>\n");
fprintf(f, "</UnstructuredGrid>\n");
fprintf(f, "</VTKFile>\n");
fclose(f);
}
......
......@@ -27,7 +27,7 @@ double *particleProblemPosition(ParticleProblem *p);
double *particleProblemExternalForces(ParticleProblem *p);
unsigned long int particleProblemNParticle(ParticleProblem *p);
void particleProblemUseJacobi(ParticleProblem *p, int jacobi, double relax);
void particleProblemWriteVtk(ParticleProblem *p, const char *filename);
int particleProblemWriteVtk(ParticleProblem *p, const char *filename);
void particleProblemWriteBoundaryVtk(ParticleProblem *p, const char *filename);
double *particleProblemRadius(ParticleProblem *p);
int *particleProblemDiskTag(ParticleProblem *p);
......
......@@ -81,7 +81,7 @@ class ParticleProblem :
shutil.move(fname+"_tmp", fname)
def write_vtk(self, odir, i, t) :
outputname = "%s/part-%05i.vtp" % (odir, i)
outputname = "%s/part-%05i.vtu" % (odir, i)
lib.particleProblemWriteVtk(self._p, (outputname+"_tmp").encode())
shutil.move(outputname + "_tmp", outputname)
......
......@@ -81,7 +81,7 @@ class ParticleProblem :
shutil.move(fname+"_tmp", fname)
def write_vtk(self, odir, i, t) :
outputname = "%s/part-%05i.vtp" % (odir, i)
outputname = "%s/part-%05i.vtu" % (odir, i)
lib.particleProblemWriteVtk(self._p, (outputname+"_tmp").encode())
shutil.move(outputname + "_tmp", outputname)
......
......@@ -123,6 +123,115 @@ int fluid_problem_export(const FluidProblem *problem, const char *output_dir, do
return 0;
}
int fluid_problem_export_vtk(const FluidProblem *problem, const char *output_dir, double t, int iter)
{
Mesh *mesh = problem->mesh;
char file_name[1024];
sprintf(file_name,"%s/fluid_%05i.vtu",output_dir, iter);
FILE *f = fopen(file_name, "w");
if (!f){
printf("Cannot open file \"%s\" for writing.\n", file_name);
return -1;
}
fprintf(f,"<VTKFile type=\"UnstructuredGrid\" format=\"0.1\">\n");
fprintf(f,"<UnstructuredGrid>\n");
fprintf(f,"<Piece NumberOfPoints=\"%i\" NumberOfCells=\"%i\">\n", mesh->n_nodes, mesh->n_elements);
fprintf(f,"<Points>\n");
fprintf(f,"<DataArray NumberOfComponents=\"3\" type=\"Float64\" format=\"ascii\">\n");
for (int i = 0; i < 3*mesh->n_nodes; ++i) {
fprintf(f,"%g ", mesh->x[i]);
}
fprintf(f,"\n</DataArray>\n");
fprintf(f,"</Points>\n");
fprintf(f,"<Cells>\n");
fprintf(f,"<DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">\n");
for (int i = 0; i < mesh->n_elements*3; ++i) {
fprintf(f,"%i ", mesh->elements[i]);
}
fprintf(f,"\n</DataArray>\n");
fprintf(f,"<DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">\n");
for(int i = 0; i < mesh->n_elements;++i) {
fprintf(f,"%i ", (i+1)*3);
}
fprintf(f,"\n</DataArray>\n");
fprintf(f,"<DataArray type=\"Int32\" Name=\"types\" format=\"ascii\">\n");
for (int i = 0; i < mesh->n_elements; ++i) {
fprintf(f,"%i ", 5); // 10 for 3d
}
fprintf(f,"\n</DataArray>\n");
fprintf(f,"</Cells>\n");
//fprintf(f,"<PointData Scalars=\"Pressure Porosity\" Vectors=\"Velocity\">\n");
fprintf(f,"<PointData Scalars=\"Porosity Pressure\" Vectors=\"Velocity\">\n");
fprintf(f,"<DataArray Name=\"Porosity\" NumberOfComponents = \"1\" type=\"Float64\" format=\"ascii\">\n");
for (int i = 0; i < mesh->n_nodes; ++i) {
fprintf(f, "%g ", problem->porosity[i]);
}
fprintf(f,"\n</DataArray>\n");
fprintf(f,"<DataArray Name=\"Pressure\" NumberOfComponents = \"1\" type=\"Float64\" format=\"ascii\">\n");
for (int i = 0; i < mesh->n_nodes; ++i) {
fprintf(f, "%g ", problem->solution[i*(DIMENSION+1)+DIMENSION]);
}
fprintf(f,"\n</DataArray>\n");
fprintf(f,"<DataArray Name=\"Velocity\" NumberOfComponents = \"3\" type=\"Float64\" format=\"ascii\">\n");
for (int i = 0; i < mesh->n_nodes; ++i) {
for (int j = 0; j < DIMENSION; ++j)
fprintf(f, "%g ", problem->solution[i*(DIMENSION+1)+j]);
if(DIMENSION==2)
fprintf(f, "0 ");
}
fprintf(f,"\n</DataArray>\n");
fprintf(f,"</PointData>\n");
fprintf(f,"</Piece>\n");
fprintf(f,"</UnstructuredGrid>\n");
fprintf(f,"</VTKFile>\n");
//t[:] = 5 if dim == 2 else 10
/*
output = open("%s/f_%05i.vtu" %(odir, oiter), "w")
vertices = np.array(self._mesh.vertices)[:,:3]
elements = np.array([[v[3] for v in e.vertices] for e in self._dof.getElements(0)], np.int32) -1
v = np.zeros((vertices.shape[0], 3))
for d in range (dim) :
v[elements, d] = self._jac.x[:,:,d]
output.write("<Cells>\n")
output.write("<DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">\n")
np.savetxt(output, elements, fmt="%i")
output.write("</DataArray>\n")
output.write("<DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">\n")
np.savetxt(output, (np.array(range(elements.shape[0]), np.int32)+1)*(dim+1), fmt="%i", newline=" ")
output.write("</DataArray>\n")
output.write("<DataArray type=\"Int32\" Name=\"types\" format=\"ascii\">\n")
t = np.ndarray((elements.shape[0]), np.int32)
np.savetxt(output, t, fmt="%i", newline=" ")
output.write("</DataArray>\n")
output.write("</Cells>\n")
output.write("<PointData Scalars=\"Pressure Porosity\" Vectors=\"Velocity\">\n")
output.write("<DataArray Name=\"Porosity\" NumberOfComponents = \"1\" type=\"Float64\" format=\"ascii\">")
p = np.ndarray((vertices.shape[0]))
p[np.transpose(elements)] = self._jac.dofManager.getField(0, self._pf.porosity)
np.savetxt(output, p)
output.write("</DataArray>\n")
output.write("<DataArray Name=\"Pressure\" NumberOfComponents = \"1\" type=\"Float64\" format=\"ascii\">")
p[np.transpose(elements)] = self._dof.getField(dim, self._sol)
np.savetxt(output, p)
output.write("</DataArray>\n")
output.write("<DataArray Name=\"Velocity\" NumberOfComponents = \"3\" type=\"Float64\" format=\"ascii\">")
v = np.zeros((vertices.shape[0], 3))
for d in range (self._jac.dim) :
v[np.transpose(elements), d] = self._dof.getField(d, self._sol)[:self._jac.dim+1,:]
np.savetxt(output, v)
output.write("</DataArray>\n")
output.write("</PointData>\n")
output.write("</Piece>\n")
output.write("</UnstructuredGrid>\n")
output.write("</VTKFile>\n")
*/
fclose(f);
return 0;
}
#if DIMENSION == 2
static void particle_drag(double u[2], double mu, double rho, double d, double c, double drag[2], double dt, double mass, double rhop, double gradp[2])
{
......
......@@ -36,6 +36,7 @@ typedef struct {
} FluidProblem;
int fluid_problem_export(const FluidProblem *problem, const char *output_dir, double t, int iter);
int fluid_problem_export_vtk(const FluidProblem *problem, const char *output_dir, double t, int iter);
// complete force on the particle (including gravity)
void fluid_problem_compute_node_particle_force(FluidProblem *problem, double dt, double *particle_force);
void fluid_problem_implicit_euler(FluidProblem *problem, double dt);
......
# See blog for details: https://blog.kitware.com/easy-customization-of-the-paraview-python-programmable-filter-property-panel/
import os
import sys
import inspect
import textwrap
def escapeForXmlAttribute(s):
# http://www.w3.org/TR/2000/WD-xml-c14n-20000119.html#charescaping
# In character data and attribute values, the character information items "<" and "&" are represented by "&lt;" and "&amp;" respectively.
# In attribute values, the double-quote character information item (") is represented by "&quot;".
# In attribute values, the character information items TAB (#x9), newline (#xA), and carriage-return (#xD) are represented by "&#x9;", "&#xA;", and "&#xD;" respectively.
s = s.replace('&', '&amp;') # Must be done first!
s = s.replace('<', '&lt;')
s = s.replace('>', '&gt;')
s = s.replace('"', '&quot;')
s = s.replace('\r', '&#xD;')
s = s.replace('\n', '&#xA;')
s = s.replace('\t', '&#x9;')
return s
def getScriptPropertiesXml(info):
e = escapeForXmlAttribute
requestData = e(info['RequestData'])
requestInformation = e(info['RequestInformation'])
requestUpdateExtent = e(info['RequestUpdateExtent'])
if requestData:
requestData = '''
<StringVectorProperty
name="Script"
command="SetScript"
number_of_elements="1"
default_values="%s"
panel_visibility="advanced">
<Hints>
<Widget type="multi_line"/>
</Hints>
<Documentation>This property contains the text of a python program that
the programmable source runs.</Documentation>
</StringVectorProperty>''' % requestData
if requestInformation:
requestInformation = '''
<StringVectorProperty
name="InformationScript"
label="RequestInformation Script"
command="SetInformationScript"
number_of_elements="1"
default_values="%s"
panel_visibility="advanced">
<Hints>
<Widget type="multi_line" />
</Hints>
<Documentation>This property is a python script that is executed during
the RequestInformation pipeline pass. Use this to provide information
such as WHOLE_EXTENT to the pipeline downstream.</Documentation>
</StringVectorProperty>''' % requestInformation
if requestUpdateExtent:
requestUpdateExtent = '''
<StringVectorProperty
name="UpdateExtentScript"
label="RequestUpdateExtent Script"
command="SetUpdateExtentScript"
number_of_elements="1"
default_values="%s"
panel_visibility="advanced">
<Hints>
<Widget type="multi_line" />
</Hints>
<Documentation>This property is a python script that is executed during
the RequestUpdateExtent pipeline pass. Use this to modify the update
extent that your filter ask up stream for.</Documentation>
</StringVectorProperty>''' % requestUpdateExtent
return '\n'.join([requestData, requestInformation, requestUpdateExtent])
def getPythonPathProperty():
return '''
<StringVectorProperty command="SetPythonPath"
name="PythonPath"
number_of_elements="1"
panel_visibility="advanced">
<Documentation>A semi-colon (;) separated list of directories to add to
the python library search path.</Documentation>
</StringVectorProperty>'''
def getFilterPropertyXml(propertyInfo, propertyName):
e = escapeForXmlAttribute
propertyValue = propertyInfo[propertyName]
propertyLabel = propertyName.replace('_', ' ')
if isinstance(propertyValue, list):
numberOfElements = len(propertyValue)
assert numberOfElements > 0
propertyType = type(propertyValue[0])
defaultValues = ' '.join([str(v) for v in propertyValue])
else:
numberOfElements = 1
propertyType = type(propertyValue)
defaultValues = str(propertyValue)
if propertyType is bool:
defaultValues = defaultValues.replace('True', '1').replace('False', '0')
return '''
<IntVectorProperty
name="%s"
label="%s"
initial_string="%s"
command="SetParameter"
animateable="1"
default_values="%s"
number_of_elements="%s">
<BooleanDomain name="bool" />
<Documentation></Documentation>
</IntVectorProperty>''' % (propertyName, propertyLabel, propertyName, defaultValues, numberOfElements)
if propertyType is int:
return '''
<IntVectorProperty
name="%s"
label="%s"
initial_string="%s"
command="SetParameter"
animateable="1"
default_values="%s"
number_of_elements="%s">
<Documentation></Documentation>
</IntVectorProperty>''' % (propertyName, propertyLabel, propertyName, defaultValues, numberOfElements)
if propertyType is float:
return '''
<DoubleVectorProperty
name="%s"
label="%s"
initial_string="%s"
command="SetParameter"
animateable="1"
default_values="%s"
number_of_elements="%s">
<Documentation></Documentation>
</DoubleVectorProperty>''' % (propertyName, propertyLabel, propertyName, defaultValues, numberOfElements)
if propertyType is str:
return '''
<StringVectorProperty
name="%s"
label="%s"
initial_string="%s"
command="SetParameter"
animateable="1"
default_values="%s"
number_of_elements="%s">
<Documentation></Documentation>
</StringVectorProperty>''' % (propertyName, propertyLabel, propertyName, defaultValues, numberOfElements)
raise Exception('Unknown property type: %r' % propertyType)
def getFilterPropertiesXml(info):