def __init__(self, Model, settings):
        """ The default constructor of the class

        Keyword arguments:
        self -- It signifies an instance of a class.
        Model -- the container of the different model parts.
        settings -- Kratos parameters containing solver settings.
        """

        KratosMultiphysics.Process.__init__(self)

        default_settings = KratosMultiphysics.Parameters("""
        {
            "help"                 : "This process assigns a given value (vector) to the nodes belonging a certain submodelpart",
            "mesh_id"              : 0,
            "model_part_name"      : "please_specify_model_part_name",
            "variable_name"        : "SPECIFY_VARIABLE_NAME",
            "interval"             : [0.0, 1e30],
            "value"                : [10.0, "3*t", "x+y"],
            "constrained"          : [true,true,true],
            "local_axes"           : {}
        }
        """)
        #example of admissible values for "value" : [10.0, "3*t", "x+y"]

        ## Trick to ensure that if someone sets constrained as a single bool, it is transformed to a vector
        if settings.Has("constrained"):
            if settings["constrained"].IsBool():
                is_fixed = settings["constrained"].GetBool()
                #print("is_fixed = ",is_fixed)
                settings["constrained"] = default_settings["constrained"]
                for i in range(3):
                    settings["constrained"][i].SetBool(is_fixed)

        settings.ValidateAndAssignDefaults(default_settings)

        self.variable = KratosMultiphysics.KratosGlobals.GetVariable(
            settings["variable_name"].GetString())
        if not isinstance(
                self.variable,
                KratosMultiphysics.Array1DVariable3) and not isinstance(
                    self.variable, KratosMultiphysics.VectorVariable):
            msg = "Error in AssignVectorVariableProcess. Variable type of variable : " + settings[
                "variable_name"].GetString(
                ) + " is incorrect . Must be a vector or array3"
            raise Exception(msg)

        self.model_part = Model[settings["model_part_name"].GetString()]

        self.aux_processes = []

        # Loop over components X, Y and Z
        for indice, variable in enumerate(["_X", "_Y", "_Z"]):
            if not settings["value"][indice].IsNull():
                i_params = KratosMultiphysics.Parameters("{}")
                i_params.AddValue("model_part_name",
                                  settings["model_part_name"])
                i_params.AddValue("mesh_id", settings["mesh_id"])
                i_params.AddEmptyValue("constrained").SetBool(
                    settings["constrained"][indice].GetBool())
                i_params.AddValue("interval", settings["interval"])
                i_params.AddValue("value", settings["value"][indice])
                i_params.AddEmptyValue("variable_name").SetString(
                    settings["variable_name"].GetString() + variable)
                i_params.AddValue("local_axes", settings["local_axes"])
                self.aux_processes.append(
                    assign_scalar_variable_process.AssignScalarVariableProcess(
                        Model, i_params))
    def __init__(self, Model, settings):
        """ The default constructor of the class

        Keyword arguments:
        self -- It signifies an instance of a class.
        Model -- the container of the different model parts.
        settings -- Kratos parameters containing solver settings.
        """
        KratosMultiphysics.Process.__init__(self)

        default_settings = KratosMultiphysics.Parameters("""
        {
            "help"                 : "This process sets a variable a certain scalar value in a given direction, for all the nodes belonging to a submodelpart. Uses assign_scalar_variable_to_conditions_process for each component",
            "mesh_id"              : 0,
            "model_part_name"      : "please_specify_model_part_name",
            "variable_name"        : "SPECIFY_VARIABLE_NAME",
            "interval"             : [0.0, 1e30],
            "modulus"              : 1.0,
            "constrained"          : true,
            "direction"            : [1.0, 0.0, 0.0],
            "local_axes"           : {}
        }
        """)

        # Trick: allow "modulus" and "direction" to be a double or a string value (otherwise the ValidateAndAssignDefaults might fail)
        if settings.Has("modulus"):
            if settings["modulus"].IsString():
                default_settings["modulus"].SetString("0.0")

        if settings.Has("direction"):
            if settings["direction"].IsString():
                default_settings["direction"].SetString("Automatic")

        # Detect "End" as a tag and replace it by a large number
        if settings.Has("interval"):
            if settings["interval"][1].IsString():
                if settings["interval"][1].GetString() == "End":
                    settings["interval"][1].SetDouble(
                        1e30)  # = default_settings["interval"][1]
                else:
                    raise Exception(
                        "The second value of interval can be \"End\" or a number, interval currently:"
                        + settings["interval"].PrettyPrintJsonString())

        settings.ValidateAndAssignDefaults(default_settings)

        self.model_part = Model[settings["model_part_name"].GetString()]

        # Construct the component by component parameter objects
        x_params = KratosMultiphysics.Parameters("{}")
        y_params = KratosMultiphysics.Parameters("{}")
        z_params = KratosMultiphysics.Parameters("{}")

        list_params = [x_params, y_params, z_params]
        for i_dir, var_string in enumerate(["_X", "_Y", "_Z"]):
            list_params[i_dir].AddValue("model_part_name",
                                        settings["model_part_name"])
            list_params[i_dir].AddValue("mesh_id", settings["mesh_id"])
            list_params[i_dir].AddValue("constrained", settings["constrained"])
            list_params[i_dir].AddValue("interval", settings["interval"])
            list_params[i_dir].AddEmptyValue("variable_name").SetString(
                settings["variable_name"].GetString() + var_string)
            list_params[i_dir].AddValue("local_axes", settings["local_axes"])

        # "Automatic" direction: get the inwards direction
        all_numeric = True
        if settings["direction"].IsString():
            if settings["direction"].GetString(
            ) == "automatic_inwards_normal" or settings["direction"].GetString(
            ) == "automatic_outwards_normal":
                # Compute the condition normals
                KratosMultiphysics.NormalCalculationUtils().CalculateOnSimplex(
                    self.model_part, self.model_part.ProcessInfo[
                        KratosMultiphysics.DOMAIN_SIZE])

                # Compute the average conditions normal in the submodelpart of interest
                avg_normal = KratosMultiphysics.VariableUtils(
                ).SumConditionVectorVariable(KratosMultiphysics.NORMAL,
                                             self.model_part)
                avg_normal_norm = math.sqrt(
                    pow(avg_normal[0], 2) + pow(avg_normal[1], 2) +
                    pow(avg_normal[2], 2))
                if avg_normal_norm < 1.0e-6:
                    raise Exception(
                        "Direction norm is close to 0 in AssignVectorByDirectionProcess."
                    )

                unit_direction = KratosMultiphysics.Vector(3)
                unit_direction = (1.0 / avg_normal_norm) * avg_normal

                # Note that the NormalCalculationUtils().CalculateOnSimplex gives the outwards normal vector
                if settings["direction"].GetString(
                ) == "automatic_inwards_normal":
                    unit_direction = (-1) * unit_direction
        # Direction is given as a vector
        elif settings["direction"].IsArray():
            unit_direction = [0.0, 0.0, 0.0]
            direction_norm = 0.0
            for i in range(0, 3):
                if settings["direction"][i].IsNumber():
                    unit_direction[i] = settings["direction"][i].GetDouble()
                    direction_norm += pow(unit_direction[i], 2)
                else:
                    function_string = settings["direction"][i].GetString()
                    unit_direction[i] = function_string
                    all_numeric = False

            # Normalize direction
            if all_numeric:
                direction_norm = math.sqrt(direction_norm)
                if direction_norm < 1.0e-6:
                    raise Exception(
                        "Direction norm is close to 0 in AssignVectorByDirectionProcess."
                    )
                for i in range(0, 3):
                    unit_direction[i] = unit_direction[i] / direction_norm

        # Set the remainding parameters
        if settings["modulus"].IsNumber():
            modulus = settings["modulus"].GetDouble()
            if all_numeric:
                for i_dir in range(3):
                    list_params[i_dir].AddEmptyValue("value").SetDouble(
                        modulus * unit_direction[i_dir])
            else:
                for i_dir in range(3):
                    list_params[i_dir].AddEmptyValue(
                        "value").SetString("(" + str(unit_direction[i_dir]) +
                                           ")*(" + str(modulus) + ")")
        elif settings["modulus"].IsString():
            # The concatenated string is: "direction[i])*(f(x,y,z,t)"
            modulus = settings["modulus"].GetString()
            for i_dir in range(3):
                list_params[i_dir].AddEmptyValue("value").SetString(
                    "(" + str(unit_direction[i_dir]) + ")*(" + modulus + ")")

        # Construct a AssignScalarToNodesProcess for each component
        self.aux_processes = []
        for i_dir in range(3):
            self.aux_processes.append(
                assign_scalar_variable_process.AssignScalarVariableProcess(
                    Model, list_params[i_dir]))