Commit 0f24409e authored by Sebastian Eibl's avatar Sebastian Eibl
Browse files

- new frontend for MESA-PD

- added ability to create custom modules
parent 571b86e7
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
from mesa_pd.accessor import Accessor
from mesa_pd import Module
import mesa_pd.data as data
import mesa_pd.kernel as kernel
import mesa_pd.mpi as mpi
......@@ -11,136 +11,107 @@ import numpy as np
import os
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Generate all necessary files for the waLBerla mesa_pd module.')
parser.add_argument('path', help='Where should the files be created?')
parser.add_argument("-f", "--force", help="Generate the files even if not inside a waLBerla directory.",
action="store_true")
args = parser.parse_args()
if ((not os.path.isfile(args.path + "/src/walberla.h")) and (not args.force)):
raise RuntimeError(args.path + " is not the path to a waLBerla root directory! Specify -f to generate the files anyway.")
os.makedirs(args.path + "/src/mesa_pd/common", exist_ok = True)
os.makedirs(args.path + "/src/mesa_pd/data", exist_ok = True)
os.makedirs(args.path + "/src/mesa_pd/domain", exist_ok = True)
os.makedirs(args.path + "/src/mesa_pd/kernel", exist_ok = True)
os.makedirs(args.path + "/src/mesa_pd/mpi/notifications", exist_ok = True)
os.makedirs(args.path + "/src/mesa_pd/vtk", exist_ok = True)
shapes = ["Sphere", "HalfSpace", "CylindricalBoundary", "Box", "Ellipsoid"]
ps = data.ParticleStorage()
ch = data.ContactHistory()
lc = data.LinkedCells()
slc = data.SparseLinkedCells()
ss = data.ShapeStorage(ps, shapes)
cs = data.ContactStorage()
ps.addProperty("position", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ALWAYS")
ps.addProperty("linearVelocity", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ALWAYS")
ps.addProperty("invMass", "walberla::real_t", defValue="real_t(1)", syncMode="ON_GHOST_CREATION")
ps.addProperty("force", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.addProperty("oldForce", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ON_OWNERSHIP_CHANGE")
ps.addProperty("shapeID", "size_t", defValue="", syncMode="ON_GHOST_CREATION")
ps.addProperty("rotation", "walberla::mesa_pd::Rot3", defValue="", syncMode="ALWAYS")
ps.addProperty("angularVelocity", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ALWAYS")
ps.addProperty("torque", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.addProperty("oldTorque", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ON_OWNERSHIP_CHANGE")
ps.addInclude("blockforest/BlockForest.h")
ps.addProperty("currentBlock", "blockforest::BlockID", defValue="", syncMode="NEVER")
ps.addProperty("type", "uint_t", defValue="0", syncMode="ON_GHOST_CREATION")
ps.addProperty("flags", "walberla::mesa_pd::data::particle_flags::FlagT", defValue="", syncMode="ON_GHOST_CREATION")
ps.addProperty("nextParticle", "int", defValue="-1", syncMode="NEVER")
ps.addProperty("oldContactHistory", "std::map<walberla::id_t, walberla::mesa_pd::data::ContactHistory>", defValue="", syncMode="ALWAYS")
ps.addProperty("newContactHistory", "std::map<walberla::id_t, walberla::mesa_pd::data::ContactHistory>", defValue="", syncMode="NEVER")
ps.addProperty("temperature", "walberla::real_t", defValue="real_t(0)", syncMode="ALWAYS")
ps.addProperty("heatFlux", "walberla::real_t", defValue="real_t(0)", syncMode="NEVER")
# Properties for HCSITS
ps.addProperty("dv", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.addProperty("dw", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
# Properties for lbm_mesapd_coupling:
ps.addProperty("hydrodynamicForce", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.addProperty("hydrodynamicTorque", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.addProperty("oldHydrodynamicForce", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.addProperty("oldHydrodynamicTorque", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ch.addProperty("tangentialSpringDisplacement", "walberla::mesa_pd::Vec3", defValue="real_t(0)")
ch.addProperty("isSticking", "bool", defValue="false")
ch.addProperty("impactVelocityMagnitude", "real_t", defValue="real_t(0)")
cs.addProperty("id1", "walberla::id_t", defValue = "walberla::id_t(-1)", syncMode="NEVER")
cs.addProperty("id2", "walberla::id_t", defValue = "walberla::id_t(-1)", syncMode="NEVER")
cs.addProperty("distance", "real_t", defValue = "real_t(1)", syncMode="NEVER")
cs.addProperty("normal", "walberla::mesa_pd::Vec3", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("position", "walberla::mesa_pd::Vec3", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("t", "walberla::mesa_pd::Vec3", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("o", "walberla::mesa_pd::Vec3", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("r1", "walberla::mesa_pd::Vec3", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("r2", "walberla::mesa_pd::Vec3", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("mu", "real_t", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("p", "walberla::mesa_pd::Vec3", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("diag_nto", "walberla::mesa_pd::Mat3", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("diag_nto_inv", "walberla::mesa_pd::Mat3", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("diag_to_inv", "walberla::mesa_pd::Mat2", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("diag_n_inv", "real_t", defValue = "real_t(0)", syncMode="NEVER")
cs.addProperty("p", "walberla::mesa_pd::Vec3", defValue = "real_t(0)", syncMode="NEVER")
kernels = []
kernels.append( kernel.DetectAndStoreContacts() )
kernels.append( kernel.DoubleCast(shapes) )
kernels.append( kernel.ExplicitEuler() )
kernels.append( kernel.ExplicitEulerWithShape() )
kernels.append( kernel.ForceLJ() )
kernels.append( kernel.HCSITSRelaxationStep() )
kernels.append( kernel.HeatConduction() )
kernels.append( kernel.InitParticlesForHCSITS() )
kernels.append( kernel.InitContactsForHCSITS() )
kernels.append( kernel.IntegrateParticlesHCSITS() )
kernels.append( kernel.InsertParticleIntoLinkedCells() )
kernels.append( kernel.InsertParticleIntoSparseLinkedCells() )
kernels.append( kernel.LinearSpringDashpot() )
kernels.append( kernel.NonLinearSpringDashpot() )
kernels.append( kernel.SingleCast(shapes) )
kernels.append( kernel.SpringDashpot() )
kernels.append( kernel.TemperatureIntegration() )
kernels.append( kernel.VelocityVerlet() )
kernels.append( kernel.VelocityVerletWithShape() )
ac = Accessor()
for k in kernels:
ac.mergeRequirements(k.getRequirements())
ac.printSummary()
comm = []
comm.append(mpi.BroadcastProperty())
comm.append(mpi.ClearNextNeighborSync())
comm.append(mpi.ReduceContactHistory())
comm.append(mpi.ReduceProperty())
comm.append(mpi.ShapePackUnpack(shapes))
comm.append(mpi.SyncGhostOwners(ps))
comm.append(mpi.SyncNextNeighbors(ps))
ps.generate(args.path + "/src/mesa_pd/")
ch.generate(args.path + "/src/mesa_pd/")
lc.generate(args.path + "/src/mesa_pd/")
slc.generate(args.path + "/src/mesa_pd/")
ss.generate(args.path + "/src/mesa_pd/")
cs.generate(args.path + "/src/mesa_pd/")
for k in kernels:
k.generate(args.path + "/src/mesa_pd/")
for c in comm:
c.generate(args.path + "/src/mesa_pd/")
parser = argparse.ArgumentParser(description='Generate all necessary files for the waLBerla mesa_pd module.')
parser.add_argument('path', help='Where should the files be created?')
args = parser.parse_args()
mpd = Module(args.path)
ps = mpd.add(data.ParticleStorage())
ps.set_shapes('Sphere', 'HalfSpace', 'CylindricalBoundary', 'Box', 'Ellipsoid')
ps.add_property("position", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ALWAYS")
ps.add_property("linearVelocity", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ALWAYS")
ps.add_property("invMass", "walberla::real_t", defValue="real_t(1)", syncMode="ON_GHOST_CREATION")
ps.add_property("force", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.add_property("oldForce", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ON_OWNERSHIP_CHANGE")
ps.add_property("shapeID", "size_t", defValue="", syncMode="ON_GHOST_CREATION")
ps.add_property("rotation", "walberla::mesa_pd::Rot3", defValue="", syncMode="ALWAYS")
ps.add_property("angularVelocity", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ALWAYS")
ps.add_property("torque", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.add_property("oldTorque", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ON_OWNERSHIP_CHANGE")
ps.add_include("blockforest/BlockForest.h")
ps.add_property("currentBlock", "blockforest::BlockID", defValue="", syncMode="NEVER")
ps.add_property("type", "uint_t", defValue="0", syncMode="ON_GHOST_CREATION")
ps.add_property("flags", "walberla::mesa_pd::data::particle_flags::FlagT", defValue="",
syncMode="ON_GHOST_CREATION")
ps.add_property("nextParticle", "int", defValue="-1", syncMode="NEVER")
ps.add_property("oldContactHistory", "std::map<walberla::id_t, walberla::mesa_pd::data::ContactHistory>",
defValue="", syncMode="ALWAYS")
ps.add_property("newContactHistory", "std::map<walberla::id_t, walberla::mesa_pd::data::ContactHistory>",
defValue="", syncMode="NEVER")
ps.add_property("temperature", "walberla::real_t", defValue="real_t(0)", syncMode="ALWAYS")
ps.add_property("heatFlux", "walberla::real_t", defValue="real_t(0)", syncMode="NEVER")
# Properties for HCSITS
ps.add_property("dv", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.add_property("dw", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
# Properties for lbm_mesapd_coupling:
ps.add_property("hydrodynamicForce", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.add_property("hydrodynamicTorque", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.add_property("oldHydrodynamicForce", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ps.add_property("oldHydrodynamicTorque", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER")
ch = mpd.add(data.ContactHistory())
ch.add_property("tangentialSpringDisplacement", "walberla::mesa_pd::Vec3", defValue="real_t(0)")
ch.add_property("isSticking", "bool", defValue="false")
ch.add_property("impactVelocityMagnitude", "real_t", defValue="real_t(0)")
cs = mpd.add(data.ContactStorage())
cs.add_property("id1", "walberla::id_t", defValue="walberla::id_t(-1)")
cs.add_property("id2", "walberla::id_t", defValue="walberla::id_t(-1)")
cs.add_property("distance", "real_t", defValue="real_t(1)")
cs.add_property("normal", "walberla::mesa_pd::Vec3", defValue="real_t(0)")
cs.add_property("position", "walberla::mesa_pd::Vec3", defValue="real_t(0)")
cs.add_property("t", "walberla::mesa_pd::Vec3", defValue="real_t(0)")
cs.add_property("o", "walberla::mesa_pd::Vec3", defValue="real_t(0)")
cs.add_property("r1", "walberla::mesa_pd::Vec3", defValue="real_t(0)")
cs.add_property("r2", "walberla::mesa_pd::Vec3", defValue="real_t(0)")
cs.add_property("mu", "real_t", defValue="real_t(0)")
cs.add_property("p", "walberla::mesa_pd::Vec3", defValue="real_t(0)")
cs.add_property("diag_nto", "walberla::mesa_pd::Mat3", defValue="real_t(0)")
cs.add_property("diag_nto_inv", "walberla::mesa_pd::Mat3", defValue="real_t(0)")
cs.add_property("diag_to_inv", "walberla::mesa_pd::Mat2", defValue="real_t(0)")
cs.add_property("diag_n_inv", "real_t", defValue="real_t(0)")
cs.add_property("p", "walberla::mesa_pd::Vec3", defValue="real_t(0)")
mpd.add(data.LinkedCells())
mpd.add(data.SparseLinkedCells())
mpd.add(data.ShapeStorage(ps))
mpd.add(kernel.DetectAndStoreContacts())
mpd.add(kernel.DoubleCast(ps))
mpd.add(kernel.ExplicitEuler())
mpd.add(kernel.ExplicitEulerWithShape())
mpd.add(kernel.ForceLJ())
mpd.add(kernel.HCSITSRelaxationStep())
mpd.add(kernel.HeatConduction())
mpd.add(kernel.InitParticlesForHCSITS())
mpd.add(kernel.InitContactsForHCSITS())
mpd.add(kernel.IntegrateParticlesHCSITS())
mpd.add(kernel.InsertParticleIntoLinkedCells())
mpd.add(kernel.InsertParticleIntoSparseLinkedCells())
mpd.add(kernel.LinearSpringDashpot())
mpd.add(kernel.NonLinearSpringDashpot())
mpd.add(kernel.SingleCast(ps))
mpd.add(kernel.SpringDashpot())
mpd.add(kernel.TemperatureIntegration())
mpd.add(kernel.VelocityVerlet())
mpd.add(kernel.VelocityVerletWithShape())
mpd.add(mpi.BroadcastProperty())
mpd.add(mpi.ClearNextNeighborSync())
mpd.add(mpi.Notifications(ps))
mpd.add(mpi.ReduceContactHistory())
mpd.add(mpi.ReduceProperty())
mpd.add(mpi.ShapePackUnpack(ps))
mpd.add(mpi.SyncGhostOwners(ps))
mpd.add(mpi.SyncNextNeighbors(ps))
mpd.add(mpi.SyncNextNeighborsNoGhosts(ps))
mpd.generate()
# -*- coding: utf-8 -*-
from .Property import Property, unrollDimension
from .utility import find, TerminalColor
class Container:
def __init__(self):
"""Base class for a container which manages includes and properties
"""
self.properties = []
self.includes = []
def addProperty(self, name, type, access="grs", defValue="", syncMode = "ALWAYS", dim=1):
prop = find( lambda x : x.name == name, self.properties )
if (prop == None):
#print(TerminalColor.GREEN + "creating particle property: {}".format(name) + TerminalColor.DEFAULT)
self.properties.append( Property(name, type, access=access, defValue=defValue, syncMode=syncMode, dim=dim) )
else:
if not (prop.type == type and prop.name == name and prop.defValue == defValue and prop.dim == dim):
raise RuntimeError(TerminalColor.RED + "property definition differs from previous one:\nPREVIOUS {}\nNEW {}".format(prop, Property(name, type, defValue=defValue, syncMode=syncMode, dim=dim)) + TerminalColor.DEFAULT)
print(TerminalColor.YELLOW + "reusing particle property: {}".format(name) + TerminalColor.DEFAULT)
def addInclude(self, include):
if (include in self.includes):
print(TerminalColor.YELLOW + "reusing particle include: {}".format(include) + TerminalColor.DEFAULT)
else:
#print(TerminalColor.GREEN + "creating particle include: {}".format(include) + TerminalColor.DEFAULT)
self.includes.append(include)
def unrollDimension(self):
self.properties = unrollDimension(self.properties)
# -*- coding: utf-8 -*-
from pathlib import Path
import shutil
import os
class Module:
def __init__(self, path, module_name='mesa_pd'):
"""Propery of a data strcuture
Parameters
----------
path : str
path to the root waLBerla folder
module_name : str
name of the generated module
"""
self.context = {}
self.context['path'] = Path(path).resolve()
self.context['name'] = module_name
self.context['module_path'] = self.context['path'] / 'src' / self.context['name']
self.context['test_path'] = self.context['path'] / 'tests' / self.context['name']
self.components = []
def add(self, component):
self.components.append(component)
return component
def rename(self):
for root, dirnames, filenames in os.walk(self.context['module_path']):
for filename in filenames:
filedata = None
print(f'{root}/{filename}')
with open(f'{root}/{filename}', 'r') as file:
filedata = file.read()
filedata = filedata.replace('mesa_pd', self.context['name'])
with open(f'{root}/{filename}', 'w') as file:
file.write(filedata)
def generate(self, folder_check=True):
if (folder_check):
print(f"This operation will overwrite the content of: {self.context['module_path']}")
answer = input("Continue? (y to confirm)")
if (answer != "y"):
return
mesa_pd_folder = (Path(__file__).parents[2] / 'src' / 'mesa_pd').resolve()
if (mesa_pd_folder != self.context['module_path']):
shutil.rmtree(self.context['module_path'])
shutil.copytree(mesa_pd_folder, self.context['module_path'])
for d in self.components:
d.generate(self.context)
self.rename()
\ No newline at end of file
# -*- coding: utf-8 -*-
from .utility import TerminalColor
class Property:
def __init__(self, name, type, access="grs", defValue="", syncMode = "ALWAYS", dim=1):
"""Propery of a data strcuture
Parameters
----------
name : str
name of the property
type : str
type of the property
access : str
'g' for getter (getName)
'r' for reference (getNameRef)
's' for setter (setName)
any combination is possible
defValue : str
default value the property should be initialized with
syncMode : str
'NEVER', this property does not have to be synced
'ON_GHOST_CREATION', this property must be synced on creation
'ON_OWNERSHIP_CHANGE', this property must be synced when the ownership changes
'ALWAYS', this property has to be synced in every iteration
dim : int
dimensions of the property
"""
#sort access specifier and remove duplicates
foo = "".join(sorted(access))
access = ''.join([foo[i] for i in range(len(foo)-1) if foo[i+1]!= foo[i]]+[foo[-1]])
for acc in access:
if not (acc in ["g","s","r"]):
raise RuntimeError("{} is not a valid access specifier in {}".format(acc, access))
if (not syncMode in ["NEVER", "ON_GHOST_CREATION", "ON_OWNERSHIP_CHANGE", "ALWAYS"]):
raise RuntimeError(TerminalColor.RED + "{} is no valid sync for property: {}".format(syncMode, name) + TerminalColor.DEFAULT)
if (dim < 1):
raise RuntimeError(TerminalColor.RED + "dimension has to be >=1: {}".format(dim) + TerminalColor.DEFAULT)
self.name = name
self.type = type
self.access = access
self.defValue = defValue
self.syncMode = syncMode
self.dim = dim
def __str__(self):
return "name: {}, type: {}, access: {}, defValue: {}, syncMode: {}, dim: {}".format(self.name, self.type, self.access, self.defValue, self.syncMode, self.dim)
def getAccessFunction(self):
"""Returns a list of accessor function names
"""
funcs = []
if 'g' in self.access:
funcs.append("get" + self.name.capitalize())
if 's' in self.access:
funcs.append("set" + self.name.capitalize())
if 'r' in self.access:
funcs.append("get" + self.name.capitalize() + "Ref")
return funcs
def unrollDimension(props):
"""Unrolls all more dimensional properties into one dimensional properties
Iterates over all elements. Copies all one dimensional properties.
More dimensional properties get split into one dimensional properties with added suffix.
Parameters
----------
props : list
list of properties to be unrolled
Returns
-------
list of unrolled properties
"""
unrolled = []
for prop in props:
if (prop.dim == 1):
unrolled.append(Property(prop.name, prop.type, prop.access, prop.defValue, prop.syncMode, prop.dim))
else:
for d in range(prop.dim):
unrolled.append(Property("{}{}".format(prop.name,d), prop.type, prop.access, prop.defValue, prop.syncMode, 1))
return unrolled
from .Module import Module
__all__ = ['Module']
\ No newline at end of file
# -*- coding: utf-8 -*-
from ..Property import Property
from ..utility import find, TerminalColor, generateFile
class Accessor:
def __init__(self):
self.properties = []
def require(self, name, type, access):
"""requires that a certain property is accessible
Parameters
----------
name : str
name of the property requested
type : str
type of the requested property
access : str
'g' for getter (getName)
'r' for reference (getNameRef)
's' for setter (setName)
any combination is possible
Example
-------
require("position", "walberla::mesa_pd::Vec3", "sg")
"""
prop = find( lambda x : x.name == name, self.properties )
if (prop == None):
#print(TerminalColor.GREEN + "[{}] creating particle property: {}".format(info, name) + TerminalColor.DEFAULT)
self.properties.append( Property(name, type, access = access) )
else:
if not (prop.type == type):
raise RuntimeError(TerminalColor.RED + "requirement definition differs from previous one:\n{} {}\n{} {}".format(name, type, prop.name, prop.type) + TerminalColor.DEFAULT)
foo = "".join(sorted(access + prop.access))
prop.access = ''.join([foo[i] for i in range(len(foo)-1) if foo[i+1]!= foo[i]]+[foo[-1]])
def mergeRequirements(self, accessor):
for req in accessor.properties:
self.require( req.name, req.type, req.access )
def printSummary(self):
print("="*90)
print("Requirements for Accessor:")
print("")
print("{0: <30}{1: <30}{2: <30}".format("Name", "Type", "Access"))
print("="*90)
for gs in self.properties:
print("{0: <30.29}{1: <30.29}{2: <30.29}".format(gs.name, gs.type, gs.access))
print("="*90)
def create_access(name, type, access):
"""requires that a certain property is accessible
Parameters
----------
name : str
name of the property requested
type : str
type of the requested property
access : str
'g' for getter (getName)
'r' for reference (getNameRef)
's' for setter (setName)
any combination is possible
Example
-------
create_access("position", "walberla::mesa_pd::Vec3", "sg")
"""
for acc in access:
if not (acc in ["g", "s", "r"]):
raise RuntimeError(f"{acc} is not a valid access specifier in {access}")
return {'name': name, 'type': type, 'access': access}
# -*- coding: utf-8 -*-
from .Accessor import Accessor
from .Accessor import create_access
__all__ = ['Accessor']
__all__ = ['create_access']
# -*- coding: utf-8 -*-
import numpy as np
from ..Container import Container
from ..utility import generateFile
class ContactHistory(Container):
def __init__(self):
super().__init__()
def generate(self, path):
self.unrollDimension()
print("="*90)
print("Creating ContactHistory Datastructure:")
print("")
print("{0: <20}{1: <30}{2: <20}{3: <10}".format("Type", "Name", "Def. Value", "SyncMode"))
print("="*90)
for prop in self.properties:
print("{0: <20.19}{1: <30.29}{2: <20.19}{3: <10.9}".format(prop.type, prop.name, prop.defValue, prop.syncMode))
print("="*90)
context = dict()
context["includes"] = self.includes
context["properties"] = self.properties
generateFile(path, 'data/ContactHistory.templ.h', context, filename='data/ContactHistory.h')
generateFile(path, 'mpi/notifications/ContactHistoryNotification.templ.h', context)
from ..utility import TerminalColor, find, generate_file
def create_contact_history_property(name, type, defValue=""):
"""
Parameters
----------
name : str
name of the property
type : str
type of the property
defValue : str
default value the property should be initialized with
"""
return {'name': name, 'type': type, 'defValue': defValue}
class ContactHistory():
def __init__(self):
self.context = {'includes': [], 'properties': []}
def add_property(self, name, type, defValue=""):
prop = find(lambda x: x['name'] == name, self.context['properties'])
if (prop == None):
# print(f"{TerminalColor.GREEN} creating property: {name} {TerminalColor.DEFAULT}")
self.context['properties'].append(create_contact_history_property(name, type, defValue=defValue))
else: